Введение про типы сайтов и их различие
Раньше, во времена когда меня ещё не было даже в планах и после, во времена моего детства - все сайты были статическими. То есть состояли только из HTML, CSS и небольших вставок JavaScript кода. Тогда, если ты и получал страницу, то ты знал, что это всё что может предложить сайт (в плане содержимого).
Парсить такие сайты одно удовольствие, только и знай что тебе нужно парсить и где это находится. Сейчас же, в сети большинство сайтов динамические.
Что значит динамический сайт? Это значит, что страницу которую ты видишь у себя в браузере не хранится отдельно где-то на сервере, а собирается на лету и выдаётся по готовности. То есть сайт не обязан пользоваться JS, чтобы стать динамическим, достаточно факта сборки этой страницы.
Парсить такие сайты заметно тяжелее, ибо предполагают:
- Либо точные тайминги - нельзя сразу скачивать страницу, только после того, как необходимое содержимое появится на странице
- Либо рендеринг JS - иногда требуется прямое взаимодействие с сайтом через клик, скролл или фокус на элементе, чтобы подгрузился необходимый контент, а грузится он через JS.
Подготовка, что, у кого и как будем парсить
В качестве примера парсинга, я буду использовать свой сайт. Будем парсить карточки статей (Заголовок, Ссылку и Описание).

Мой сайт использует пагинатор и динамическую подгрузку по достижению определённой высоты. Так же, хоть и не всегда, сайты могут обновлять текущий URL при загрузке нового контента, как мой. Например, поменять номер текущей страницы или добавить фильтр.
Всего существует 4 способа парсинга, а вернее получения необходимых данных с такого рода сайтов:
- Эмуляция браузеров и последующий рендеринг JS-скриптов
- Эмуляция браузера напрямую, через драйверы - Selenium
- Эмуляция браузера через специальные программный API - Playwright / Puppeteer / Cypress
2. Реверс-инжиниринг сайта и отправляемых запросов
- Использование открытого, специально-разработанного API для сторонних парсеров
- Нахождение и использование скрытого API, который не предусмотрен разработчиком
4. Получить доступ на прямую к базам данных и сайту (то есть хакнуть цель)
Я разберу только первые 3, ибо 4-й незаконен. Не взламывайте чужие сайты, пожалуйста.
Так мы напишем парсере, которые будут делать почти одно и тоже, но поразному и используя разный технологический стек. Так же рассмотрю преимущества и недостатки каждого из этих способов.
А начнём мы с первого пункта и первого подпункта - то есть через Selenium
Парсинг динамических сайтов разными способами
Парсинг сайта используя Selenium
Основным преимуществом парсинга сайта через Selenium является то, что он поддерживает огромное количество браузеров таких как: Chrome, Edge, Firefox, Safari и InternetExplorer. И не меньшее количество языков программирования: Python, Kotlin, JS, Java, C# и Ruby
Но есть один существенный недостаток, он очень медленный из-за того, что всё взаимодействие происходит через специальные драйверы, которые и эмулируют поведение браузера.
Этот парсер я буду писать на Python, соответственно и всё остальное окружение будет строиться вокруг данного языка. Создание директории и виртуальное окружение проекта, установка необходимых пакетов:
После того как была создана директория для проекта и всё настроено, добавим главный файл скрипта. В нём мы запустим веб-драйвер, сделаем первый запрос на первую страницу и сохраним её.
В общем пока что без изменений, то есть мы могли бы получить точно такую же страницу и без Selenium, но не больше. Ведь у нас ещё есть 15 страниц, которые мы не сможем получить кроме как через Selenium.
Чтобы спарсить все доступные страницы, нам нужно либо прокликать все 15 кнопок, либо пролистать вниз до конца. Сначала посмотрим как это будет выглядеть если парсить через нажатие по кнопкам:
Изначально мы можем не знать сколько нам доступно страниц, поэтому после того как мы зашли на сайт смотрим на количество доступных страниц на пагинаторе.
После создаём цикл и прокликиваем условную кнопку "Дальше", чтобы получить следующую страницу.
Но как узнать загрузилась ли страница или ещё грузиться? Есть множество вариантов если ты пользуешься Selenium, это либо указать до секунд сколько ты готов ждать, либо ждать появления, отсутствия или видимости конкретного элемента на странице, то есть использовать особый конструкт с WebDriverWait.
Без --headless флага, выглядеть это будет как-то так:
Парсинг сайта используя Playwright
Хотя Playwright, поддерживает работу с Python, я всё-таки предпочитаю работать с ним как npm-проект. В отличие от Selenium, он гораздо быстрее. Но поддерживает не все браузеры, только: Chromium(Google Chrome, Edge), WebKit(Safari), Gecko(Firefox) и их деривативы.
Так после установки playwright, чтобы спарсить все доступные статьи со страницы пагинации, можно написать следующий скрипт:
Данный парсер прокликивает кнопку "Дальше" и лишь в конце парсит всю прогрузившуюся страницу. Можно это было делать и в цикле, если бы пагинатор этого сайта просто подменял одни статьи на другие. Но так как он просто добавляет новые статьи к существующим то будет вот так.
В парсинге динамических сайтов главное усвоить такое правило. Всё требует времени, особенно если это касается пользовательского интерфейса, поэтому ожидания и обработка событий по готовности тех или иных элементов это наше всё.
Парсинг сайта используя существующий API
Это наверное самый надёжный и быстрый способ сбора данных с целевого сайта. Хотя это довольно большая редкость и занимаются этим либо крупные сайты по типу Google, либо очень маленькие сайты энтузиастов и гиков вроде меня :)
Обычно о существовании такого API, говорят прямо. Ведь это должно по идее снизить нагрузку на сервер, ведь что проще? Запрашивать 1000 HTML-страниц сайта целиком, или 100 лёгких JSON-файлов, которые уже содержат всю существующую информацию просто бери и копируй.
Вот и на моём сайте есть открытый API находящийся по вот этому адресу: https://timthewebmaster.com/api/v1/public/
Так, поигравшись немного можно выяснить что чтобы получить все необходимые статьи можно создать GET-запрос на адрес https://timthewebmaster.com/api/v1/public/article/?page=1&page_size=100&format=json и получить все статьи разом. В скрипте это будет выглядеть вот так:
Потом остаётся пройтись по полученому списку и отобрать только те данные, которые нужны. Когда такой API есть это очень сильно упрощает работу, сводя её по факту к сортировке и упаковке в более удобные и нужные форматы для заказчика.
Но опять же такой вариант очень редко встречается. Его либо не будет вообще, либо такой API будет не явным. О том, как отыскать такой API и будет следующая глава.
Парсинг сайта используя скрытый API
Скрипт будет идентичен предыдущему. Разница лишь в том, чтобы найти такой АПИ. А чтобы обнаружить такой API можно использовать консоль разработчика. В консоли зайди на вкладку Сети/Network и выбери XHR и JS. Дальше нужно повзаимодействовать со страницей (кликнуть по кнопке, навестись мышкой, проскролить вниз) и следить за перехвачеными запросами.
Данные POST-запросы, вернее ответы на них, сервер может выдавать в разных форматах. Как обычный кусок HTML-кода, так и полноценный JSON файл. Всё зависит от конкретного сайта. В моём же случае возвращается отрендеренный HTML-фрагмент, который потом придётся парсить через BeautifulSoup или другие парсеры.
Парсинг сайта через расширение для браузеров
Данный способ отлично подходит если нужно спарсить данные с сайтов под любой, даже самой крутой защитой, быстро и прямо сейчас, но заходить на такие сайты придётся реальному пользователю. Можно взять ради примера моё недавнее расширение для парсинга карточек с Avito. Этот сайт считается очень тяжёлым для парсинга, но использовав это расширение можно получить хоть и полуатоматический парсер, зато работающий.
Да, ты можешь начать извращаться и устанавливать такие расширения на Selenium или Playwright, но толку от этого будет не много. В обходе защитных механизмов от ботов это не сильно поможет.
Единственным плюсом в таком применении расширений, может быть то, что я называю "свопингом тулсета". То есть тебе удобно пробиваться через защиту например используя Python/Selenium, но парсить и собирать данные используя JS.
Заключение
Вот так вот можно парсить динамические сайты. То есть есть два путя либо имитировать поведение браузера и рендерить JS, либо искать скрытый (и не очень) АПИ этих сайтов. Конечно же и быстрее, и дешевле, и проще будет парсинг именно через такие вот АПИ, но иногда создатели сайтов сильно запариваются и делают всё возможное чтобы их рессурс не парсили.
Их можно понять, непонятно кто и зачем делает сотни и сотни запросов к веб рессурсу нагружая тем самым его и иногда даже перегружая.
По этому перед тем как начать парсинг сайта убедись в том, что не будешь слишком сильно и заметно долбить по их серверам. И соберёшь лишь самое необходимое. А если нужно потренироваться, то милости прошу долбить мой сайт :) Хорошего дня.