Динамические сайты: почему requests не хватает

На современных сайтах данных нет в исходном HTML — их рисует JavaScript.
Динамические страницы (SPA на React, Vue) приходят почти пустыми, а содержимое подгружается скриптами после загрузки. requests видит только пустой каркас. Нужен инструмент, который выполняет JavaScript.

Ты пишешь requests.get, печатаешь resp.text — и не находишь там ни товаров, ни отзывов, хотя в браузере они есть. Причина: сайт сначала отдаёт скелет страницы, а данные дотягивает JavaScript отдельными запросами к API уже после загрузки. requests и BeautifulSoup не выполняют JavaScript, поэтому видят только исходный, ещё «пустой» HTML.

Два пути для динамики

Путь 1 — найти скрытый API. Часто JavaScript сам дёргает JSON-эндпоинт. Если найти его во вкладке Network браузера (F12), можно запрашивать чистый JSON напрямую через requests — это быстрее и легче браузера. Всегда проверяй этот путь первым.

Путь 2 — управлять настоящим браузером. Если API не найти, на помощь приходят Selenium или Playwright: они запускают реальный браузер, тот выполняет JavaScript, а ты получаешь уже отрисованный HTML.

  СТАТИКА (requests хватает)        ДИНАМИКА (нужен браузер)
  ┌──────────┐                     ┌──────────┐
  │  сервер  │ -> готовый HTML     │  сервер  │ -> пустой каркас
  └──────────┘    с данными        └──────────┘       │
       │                                 │  JS-запрос к API
       v                                 v
   BeautifulSoup                   браузер исполняет JS
   парсит сразу                    -> данные появляются -> парсим

Как работает под капотом

Браузерные инструменты поднимают настоящий движок (Chromium, Firefox), который проходит весь цикл: загрузка HTML, выполнение JS, запросы к API, обновление DOM. Только после этого ты забираешь page_source — итоговую разметку с данными — и парсишь её обычным BeautifulSoup. Цена за это — скорость и ресурсы: браузер тяжёлый, поэтому его берут только когда без него никак.

Как отличить статику от динамики

Перед тем как выбирать инструмент, важно точно определить тип сайта. Простой тест: открой «Просмотр исходного кода страницы» (не инспектор, а именно сырой HTML, Ctrl+U) и поищи в нём нужные данные. Если цена и название там есть — сайт статический, хватит requests и BeautifulSoup. Если в исходнике пусто, а данные видны только в инспекторе (который показывает уже изменённый скриптами DOM) — перед тобой динамика, отрисованная JavaScript.

Обнаружив динамику, не спеши за браузером. Открой вкладку Network, перезагрузи страницу и отфильтруй запросы типа XHR/Fetch — часто там виден чистый JSON-эндпоинт, из которого сайт и берёт данные. Запросить его напрямую через requests в разы дешевле, чем поднимать Chromium: меньше кода, меньше ресурсов, выше скорость и стабильность. Настоящий браузер берут лишь тогда, когда API спрятан надёжно, защищён токенами или данные формируются исключительно на стороне клиента. Этот порядок действий — «исходник → Network → и только потом браузер» — экономит часы работы.

Частые ошибки

  • Сразу тянуть Selenium. Браузер медленный и прожорливый — сначала ищи скрытый JSON-API в Network.
  • Парсить до загрузки данных. Если забрать HTML слишком рано, данных ещё нет — нужны явные ожидания.
  • Запускать сотни браузеров параллельно. Это быстро съест память и перегрузит и тебя, и сайт.

Best practices

  • Сначала проверь вкладку Network: возможно, данные доступны как чистый JSON без браузера.
  • Браузер — крайнее средство; для статики хватает requests + BeautifulSoup.
  • Запускай браузер в headless-режиме (без окна) для экономии ресурсов на сервере.

Помни про компромисс «реализм против стоимости». Браузер максимально точно воспроизводит то, что видит человек, но дорог по ресурсам и медленен. Прямой запрос к API максимально дёшев, но требует, чтобы этот API удалось найти и он не был защищён. Опытный скрейпер всегда поднимается по этой лестнице снизу вверх: сначала простой запрос, потом поиск скрытого JSON, и только в крайнем случае — полноценный браузер. Такой порядок экономит и твоё время, и ресурсы чужого сервера.

Имеет смысл различать и два подвида динамики. Иногда данные приходят отдельным JSON-запросом после загрузки (классический AJAX) — такой эндпоинт легко поймать в Network и запросить напрямую. А иногда сервер отдаёт данные уже встроенными в страницу внутри тега <script> (например, как начальное состояние приложения в JSON) — тогда их можно достать даже из исходного HTML, аккуратно вырезав нужный фрагмент. Привычка сначала искать «где лежит чистый JSON» окупается: разбирать структурированные данные всегда надёжнее, чем цепляться за отрисованную вёрстку.

Итог: если данных нет в resp.text, их рисует JavaScript. Сначала ищи скрытый API, и только если его нет — поднимай настоящий браузер через Selenium или Playwright.

Проверьте себя
1. Почему requests часто не видит данные на современных SPA-сайтах?
Arequests работает медленно
BДанные подгружает JavaScript уже после загрузки HTML, а requests не выполняет JS
CСайт блокирует requests
Drequests не умеет читать кириллицу
2. Какой путь стоит проверить ПЕРВЫМ, прежде чем запускать браузер?
AСразу ставить Selenium
BНайти скрытый JSON-API во вкладке Network — он быстрее и легче браузера
CПерезагрузить компьютер
DОтключить JavaScript