""" Phase 0 — расширенный тест Яндекс.Карт со скроллом и извлечением полей. ЦЕЛЬ: 1. Скроллить список организаций → получить 20+ карточек (а не 5 как было) 2. Из первых 5 карточек вытащить: название, рейтинг, категорию 3. Понять структуру карточки → подготовить почву для боевого парсера ═══════════════════════════════════════════════════════════════════════ ЗАПУСК (venv уже настроен, библиотеки установлены): python test_yandex_v2.py ОЖИДАЕМЫЙ РЕЗУЛЬТАТ: - Карточек: 20-30 (после скролла) - У каждой выводится: name + rating + category ═══════════════════════════════════════════════════════════════════════ """ from botasaurus.browser import browser, Driver # Контейнер с прокручиваемым списком — пробуем несколько селекторов LIST_CONTAINER_SELECTORS = [ ".scroll__container", ".search-list-view__list", '[class*="search-list-view"]', ".results", ] CARD_SELECTOR = ".search-snippet-view" # Селекторы внутри одной карточки (тоже подбираем эмпирически) TITLE_SELECTORS = [ ".search-business-snippet-view__title", '[class*="snippet-view__title"]', '[class*="title"]', ] RATING_SELECTORS = [ ".business-rating-badge-view__rating-text", ".business-rating-badge-view__rating", '[class*="rating-badge"] [class*="rating"]', ] CATEGORY_SELECTORS = [ ".search-business-snippet-view__category", '[class*="snippet-view__category"]', '[class*="category"]', ] def find_first_text(element, selectors): """Перебор селекторов внутри карточки → текст первого найденного, либо None.""" for sel in selectors: sub = element.select(sel) if sub: text = sub.text if text: return text.strip() return None @browser( headless=False, block_images=True, reuse_driver=True, ) def test_yandex_maps_v2(driver: Driver, data: dict): query = data.get("query", "кафе") city_id = data.get("city_id", 213) url = f"https://yandex.ru/maps/{city_id}/moscow/search/{query}/" print(f"\n→ Открываю: {url}") driver.get(url) driver.sleep(5) # Проверка на бот-детектор / капчу detected = driver.get_bot_detected_by() if detected: print(f"⚠️ Бот-детектор: {detected}") return {"status": "bot_detected", "detected_by": detected} if "showcaptcha" in driver.current_url or driver.select(".CheckboxCaptcha"): print("⚠️ CAPTCHA") return {"status": "captcha"} # Найти контейнер прокручиваемого списка list_container = None for sel in LIST_CONTAINER_SELECTORS: if driver.count(sel) > 0: list_container = sel print(f"✓ Контейнер списка найден: {sel}") break # Цикл скролла — каждый раз даём время подгрузить карточки print("\n⏬ Скроллим список...") cards_before = driver.count(CARD_SELECTOR) print(f" Стартовое количество карточек: {cards_before}") MAX_SCROLLS = 10 for i in range(1, MAX_SCROLLS + 1): try: if list_container: # Скроллим именно панель списка (не окно) driver.scroll(selector=list_container, by=2000, smooth_scroll=False) else: # fallback: общий скролл окна driver.scroll(by=2000, smooth_scroll=False) except Exception as e: print(f" Скролл #{i} упал: {e}") break driver.sleep(1.5) cards_now = driver.count(CARD_SELECTOR) print(f" Скролл #{i}: карточек {cards_now}") # Если за последний скролл ничего нового не появилось — выходим if cards_now == cards_before and i >= 3: print(" Новые карточки не появляются → завершаем скролл") break cards_before = cards_now total_cards = driver.count(CARD_SELECTOR) print(f"\n✓ Итого карточек после скролла: {total_cards}") # Извлечь поля из первых 5 карточек print("\n📋 Парсим первые 5 карточек:") cards = driver.select_all(CARD_SELECTOR)[:5] parsed = [] for idx, card in enumerate(cards, start=1): name = find_first_text(card, TITLE_SELECTORS) rating = find_first_text(card, RATING_SELECTORS) category = find_first_text(card, CATEGORY_SELECTORS) parsed.append({"name": name, "rating": rating, "category": category}) print(f" [{idx}] {name!r} | rating={rating!r} | category={category!r}") return { "status": "ok", "total_cards": total_cards, "list_container_used": list_container, "sample": parsed, } if __name__ == "__main__": result = test_yandex_maps_v2({"query": "кафе", "city_id": 213}) print("\n" + "=" * 60) print("РЕЗУЛЬТАТ:") print(f" status: {result.get('status')}") print(f" total_cards: {result.get('total_cards')}") print(f" list_container_used: {result.get('list_container_used')}") print(f" sample (первые 5):") for s in result.get("sample", []): print(f" - {s}") print("=" * 60)