Scarnox · Blog

Как парсить сайты, которые рендерятся на JavaScript

Многие современные сайты присылают почти пустой HTML-документ и строят содержимое в браузере с помощью JavaScript. Если ваш парсер загружает страницу и не находит ни товаров, ни цен, ни текста статьи, содержимое есть, но приходит позже. Это руководство показывает, как понять, с каким типом страницы вы имеете дело, как найти более быстрый путь, чем браузер, где он существует, и как парсить отрисованные страницы с помощью Playwright на Python. В конце — заметка о том, что делать, если отрисованная страница показывает капчу.

Шаг 1: проверьте, есть ли содержимое в HTML

Откройте страницу через view-source: в браузере или загрузите ее простым HTTP-запросом и поищите в исходнике фрагмент текста, который видите на экране. Встречаются три варианта:

Шаг 2: вызовите JSON-эндпоинт, если он есть

Когда страница получает данные с эндпоинта, обычно лучше всего вызвать этот эндпоинт напрямую. Он меньше, быстрее и стабильнее отрисованной страницы. Скопируйте URL запроса, проверьте, какие заголовки требует сайт, и попробуйте из скрипта. Делайте это только там, где условия сайта разрешают, и соблюдайте любые ограничения частоты или аутентификацию, которых ожидает сайт. Недокументированный эндпоинт может измениться без предупреждения, поэтому пишите парсер так, чтобы он громко падал, когда структура ответа меняется.

Шаг 3: отрисовывайте страницу, когда это необходимо

Если содержимое действительно требует браузера, запустите headless-браузер. Playwright — хороший выбор для Python. Пример ниже открывает список товаров, ждет появления содержимого и читает текст из каждой карточки:

from playwright.sync_api import sync_playwright

URL = "https://example.com/products"  # страница, парсинг которой разрешен

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
    # Ждем элемент, который подтверждает, что данные загрузились.
    page.wait_for_selector(".product-card", timeout=30_000)
    titles = page.locator(".product-card h2").all_inner_texts()
    browser.close()

for title in titles:
    print(title)

Ожидание конкретного селектора намного надежнее фиксированного sleep. Фиксированная пауза либо слишком короткая в медленный день, либо тратит время в быстрый. Выберите элемент, который появляется только после загрузки данных.

Шаг 4: обрабатывайте бесконечную прокрутку и пагинацию

Некоторые страницы подгружают больше элементов при прокрутке. Прокрутите вниз, дождитесь роста числа элементов и остановитесь, когда оно перестанет расти. Страницы с нумерованной пагинацией проще: найдите ссылку на следующую страницу, перейдите по ней и остановитесь на последней. Всегда задавайте максимальное число страниц или прокруток, чтобы ошибка не заставила краулер работать вечно.

def scroll_until_done(page, selector: str, max_rounds: int = 20) -> int:
    previous = -1
    for _ in range(max_rounds):
        count = page.locator(selector).count()
        if count == previous:
            break
        previous = count
        page.mouse.wheel(0, 4000)
        page.wait_for_timeout(1500)  # даем следующей порции время загрузиться
    return previous

Шаг 5: держите браузер экономным

Отрисовка дорогая. Блокируйте изображения, шрифты и медиа, которые вам не нужны, и переиспользуйте один браузер для многих страниц вместо запуска нового каждый раз. Закрывайте страницы и контексты, когда закончите, чтобы память не росла на протяжении долгого запуска.

def block_heavy_assets(route):
    if route.request.resource_type in ("image", "font", "media"):
        route.abort()
    else:
        route.continue_()

page.route("**/*", block_heavy_assets)

Шаг 6: когда отрисованная страница показывает капчу

Иногда отрисованная страница показывает капчу до того, как показать какое-либо содержимое. Если эта капча — PopularCaptcha, живой тип капчи в Scarnox, вы читаете sitekey со страницы, запрашиваете токен и помещаете его в поле формы, которое ожидает сайт. Руководство по PopularCaptcha на Python проходит этот шаг. Другие виджеты пока не работают в режиме онлайн, поэтому проверьте типы капчи, прежде чем что-то планировать.

Будьте внимательны к самому браузеру. Headless-браузер, который явно выглядит автоматизированным, может вызвать больше проверок, а не меньше. Прочитайте обнаружение headless-браузера, чтобы понять, на какие сигналы обращать внимание, и предпочитайте более медленные загрузки страниц и их меньшее количество.

Ответственный парсинг

Следующие шаги

Начните с бесплатного пробного баланса, карта не нужна: создайте аккаунт и протестируйте поток PopularCaptcha на странице, которой вы владеете. Актуальные тарифы — на странице цен.