Files
Aks f78f35fb3f init: Parser v1 — Lead Generation Engine
Парсер лидов МБ РФ: Яндекс.Карты + HH.ru + обогащение DaData/ЕГРЮЛ/Rusprofile + Streamlit CRM.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 12:56:06 +03:00

156 lines
6.1 KiB
Python

"""
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)