Динамические сайты: почему 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.