Технологии и защита 10 мин чтения

Парсинг сайтов на Selenium: подробный обзор

Selenium для парсинга динамических сайтов: настройка драйверов, ожидания, обход детекта автоматизации и когда лучше взять API.

КP
Команда Parsing.agency
Сбор данных под задачи бизнеса
Опубликовано: 7 апреля 2025

Selenium — это инструмент для автоматизации браузера, изначально созданный для тестирования веб-приложений. Но за счёт того, что он управляет настоящим браузером, его давно и активно используют для парсинга сайтов, особенно тех, которые отдают контент через JavaScript и не открываются простым HTTP-запросом.

В этой статье разберём, как Selenium устроен, как с ним работать на разных языках, в чём его сильные и слабые стороны и почему он легко детектируется системами антибот-защиты.

Если вы только выбираете подход к парсингу, начните с наших обзоров «На каком языке писать парсер? Обзор основных решений» и «Библиотеки для парсинга сайтов» — там мы сравниваем инструменты на верхнем уровне. Эта статья — углублённый разбор одного из них.


Что такое Selenium и как он работает

Selenium управляет браузером не «изнутри», а через отдельный драйвер по протоколу WebDriver (стандарт W3C). Схема всегда одна и та же:

code
Ваш скрипт  ──▶  Selenium-биндинг  ──▶  Драйвер (chromedriver / geckodriver / …)  ──▶  Браузер
  • Биндинг — это библиотека на вашем языке (Python, Java и т. д.), которая переводит вызовы вроде driver.get(url) в команды WebDriver.
  • Драйвер — исполняемый файл-посредник для конкретного браузера: chromedriver для Chrome, geckodriver для Firefox, msedgedriver для Edge.
  • Браузер — реальный Chrome/Firefox/Edge, который рендерит страницу так же, как у обычного пользователя.

Раньше драйверы приходилось скачивать и подкладывать в PATH вручную, следя за совместимостью версий драйвера и браузера. Начиная с версии 4.6 в Selenium встроен Selenium Manager — он сам находит браузер, подбирает и скачивает нужный драйвер. На момент написания актуальная версия — Selenium 4.45 (июнь 2026). На практике это значит, что минимальный рабочий скрипт сегодня выглядит буквально в три строки, без ручной возни с драйверами.

Главное отличие от HTTP-парсеров

Обычные библиотеки (requests + BeautifulSoup, Scrapy, и т. п.) просто скачивают HTML, который сервер отдал на запрос. Если контент подгружается JavaScript-ом уже в браузере, в этом HTML его не будет.

Selenium же запускает полноценный браузер: исполняется JS, отрабатывают XHR/fetch-запросы, строится финальный DOM. Парсер видит ровно то, что видит человек. Это и есть основная причина выбирать Selenium — но за это приходится платить ресурсами и скоростью (об этом ниже).


Selenium на разных языках

Одно из главных преимуществ Selenium — официальные биндинги сразу для нескольких языков. API почти одинаковый везде, отличается только синтаксис. Это удобно: команда может писать парсер на том же языке, на котором написан остальной проект.

Официально поддерживаются: Python, Java, JavaScript (Node.js), C# (.NET) и Ruby. Для PHP, Go, Rust и других языков есть community-биндинги или обёртки, но поддерживаются они сообществом, а не основной командой Selenium.

Python

Самый популярный язык для парсинга и для Selenium в частности: низкий порог входа, огромная экосистема (pandas, lxml, BeautifulSoup для постобработки) и масса готовых примеров.

python
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example.com")

title = driver.find_element(By.TAG_NAME, "h1").text
print(title)

driver.quit()

Плюсы: самое большое комьюнити, готовые анти-детект надстройки (undetected-chromedriver, selenium-stealth, SeleniumBase), быстрая разработка. Минусы: GIL ограничивает реальную параллельность — для масштабирования обычно гоняют несколько процессов или используют Selenium Grid.

Java

Java — «родной» язык Selenium (проект исторически развивался вокруг неё) и стандарт в крупных корпоративных QA-командах.

java
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

public class Scraper {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        driver.get("https://example.com");

        String title = driver.findElement(By.tagName("h1")).getText();
        System.out.println(title);

        driver.quit();
    }
}

Плюсы: настоящая многопоточность, высокая производительность, зрелые инструменты сборки (Maven/Gradle), удобно для больших и долгоживущих систем. Минусы: многословный синтаксис, дольше писать и прототипировать, чем на Python.

JavaScript (Node.js)

Логичный выбор, если бэкенд уже на Node. Асинхронная модель (async/await) хорошо ложится на ожидание загрузки элементов.

javascript
const { Builder, By } = require("selenium-webdriver");

(async () => {
  const driver = await new Builder().forBrowser("chrome").build();
  await driver.get("https://example.com");

  const title = await driver.findElement(By.css("h1")).getText();
  console.log(title);

  await driver.quit();
})();

Плюсы: единый язык для фронта и бэка, нативная асинхронность. Минусы: в нише браузерной автоматизации на Node у Selenium есть более сильные конкуренты — Puppeteer и Playwright, которые многие предпочитают именно в JS-экосистеме.

C# (.NET)

Популярен в enterprise-окружении на стеке Microsoft.

c#
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

var driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://example.com");

var title = driver.FindElement(By.TagName("h1")).Text;
Console.WriteLine(title);

driver.Quit();

Плюсы: строгая типизация, хорошая производительность, отличная интеграция с экосистемой .NET. Минусы: меньше парсинг-ориентированных примеров и сторонних анти-детект библиотек, чем у Python.

Ruby

ruby
require "selenium-webdriver"

driver = Selenium::WebDriver.for :chrome
driver.get "https://example.com"

title = driver.find_element(tag_name: "h1").text
puts title

driver.quit

Плюсы: лаконичный, выразительный синтаксис. Минусы: относительно небольшое комьюнити в задачах парсинга, меньше готовых решений.

PHP, Go, Rust и другие

Для PHP есть php-webdriver/php-webdriver, для Go и Rust — community-обёртки. Они рабочие, но: поддерживаются сообществом, отстают по свежести фич от официальных биндингов и хуже документированы в контексте именно парсинга. Если язык вашего проекта — один из них, чаще имеет смысл рассмотреть альтернативу (например, headless-браузер через CDP или HTTP-парсер), а не тащить Selenium.


Плюсы Selenium

  • Работает с динамическими сайтами. Исполняет JavaScript и видит финальный DOM — то, что HTTP-парсеры в принципе не могут получить без эмуляции браузера.
  • Имитация реального пользователя. Клики, ввод текста, скролл, наведение, переключение вкладок, работа с куками — всё как у живого человека.
  • Кросс-языковость. Один и тот же подход на Python, Java, JS, C#, Ruby — можно остаться в стеке проекта.
  • Кросс-браузерность. Chrome, Firefox, Edge, Safari через единый API.
  • Зрелость и документация. Проекту больше 15 лет, гигантское комьюнити, ответ почти на любой вопрос уже есть на Stack Overflow.
  • Полный контроль над браузером. Скриншоты, исполнение произвольного JS, доступ к Chrome DevTools Protocol, перехват сети.

Минусы Selenium

  • Медленный и тяжёлый. Запуск полноценного браузера на каждую сессию съедает много CPU и RAM. На больших объёмах это десятки и сотни раз дороже по ресурсам, чем HTTP-запрос.
  • Плохо масштабируется «в лоб». Чтобы парсить тысячи страниц параллельно, нужен Selenium Grid, пул контейнеров или облако — это отдельная инфраструктура.
  • Хрупкость. Парсер завязан на структуру страницы и тайминги загрузки. Сменился вёрстка или поехали задержки — нужны явные ожидания (WebDriverWait), иначе всё ломается.
  • Сложнее в эксплуатации. Версии браузера и драйвера должны совпадать (Selenium Manager снимает часть боли, но не всю), браузер в Docker требует аккуратной настройки.
  • И главное — легко детектируется. Этому посвящён следующий раздел.

Почему Selenium легко определяется

Это, пожалуй, самая важная практическая проблема. Современные антибот-системы (Cloudflare, DataDome, Imperva/Incapsula, PerimeterX и др.) умеют распознавать автоматизированный браузер по множеству признаков. И «из коробки» Selenium оставляет десятки таких следов.

Основные следы, которые выдают Selenium

1. Флаг navigator.webdriver. Самый известный маркер. При запуске через WebDriver браузер выставляет navigator.webdriver = true. У обычного пользователя это свойство false или undefined. Одной строки JavaScript на стороне сайта достаточно, чтобы пометить визит как ботский.

2. Переменные $cdc_ и $wdc_. ChromeDriver внедряет в документ служебные переменные (например, начинающиеся с $cdc_). Детектор просто ищет их наличие в объекте document/window — и находит.

3. Следы Chrome DevTools Protocol (CDP). Selenium общается с Chrome через CDP. Включение домена Runtime (Runtime.Enable) детектируется отдельно — это так называемое «детектирование второго поколения», и большинство простых анти-детект библиотек его не закрывают.

4. Несоответствия в navigator. Если подменить User-Agent на iPhone, но navigator.platform остаётся Win32, число ядер (hardwareConcurrency) нетипично для заявленного устройства, а список плагинов/языков выглядит «стерильно» — антифрод ловит логическую несостыковку мгновенно.

5. Сигнатуры самих команд WebDriver. Вызовы execute_script/execute_async_script оставляют узнаваемые следы в стеке вызовов JS, по которым тоже можно распознать автоматизацию.

6. Поведенческие и сетевые признаки. Идеально ровная скорость, отсутствие движений мыши, нулевая история и куки, а также TLS-фингерпринт (JA3/JA4) и порядок заголовков, отличающиеся от настоящего браузера. Это «третье поколение» детекта.

«Поколения» детекта — чтобы было понятно, с чем боретесь

Полезно держать в голове такую градацию:

  • Поколение 1 — проверки на уровне API. navigator.webdriver, $cdc_-переменные и подобное. Закрывается анти-детект библиотеками.
  • Поколение 2 — детект на уровне протокола CDP. Например, отслеживание Runtime.Enable. Большинство популярных патчей это уже не лечат.
  • Поколение 3 — TLS-фингерпринтинг, поведенческий анализ, ML-модели под конкретного клиента. Клиентскими патчами в принципе не закрывается — тут нужны прокси, ротация, имитация поведения и качественные фингерпринты.

Инструменты, чтобы «спрятать» Selenium

Полностью убрать детект нельзя, но снизить вероятность блокировки — можно. Чаще всего используют:

  • undetected-chromedriver (Python) — патчит бинарник драйвера (убирает строку cdc_), скрывает navigator.webdriver, подгоняет опции. Долгое время считался «золотым стандартом», но закрывает в основном проблемы первого поколения.
  • selenium-stealth (Python) — набор JS-патчей: подменяет navigator.webdriver, plugins, languages, WebGL-вендора и т. п. Поддерживается слабее, чем UC.
  • SeleniumBase UC Mode — добавляет приём с disconnect/reconnect: на чувствительных действиях временно отключает ChromeDriver от браузера, обходя часть CDP-детекта.
  • nodriver — преемник undetected-chromedriver от того же автора. Работает напрямую через CDP, без chromedriver и слоя WebDriver, что устраняет ряд маркеров. Это уже не совсем «Selenium», а отдельный подход.
  • Ручные приёмы — флаг --disable-blink-features=AutomationControlled, отключение enable-automation, подмена navigator.webdriver через Page.addScriptToEvaluateOnNewDocument, согласование User-Agent с реальными свойствами navigator.

Проверить, насколько хорошо «спрятался» ваш браузер, можно на публичных тест-стендах вроде bot.sannysoft.com или сервисах фингерпринтинга.

Важная оговорка

Все эти библиотеки — не серебряная пуля. Антибот-компании изучают опенсорсные обходы: какие именно патчи накладывает undetected-chromedriver, видно прямо в его репозитории. То, что обходит защиту сегодня, может перестать работать после ближайшего обновления — без предупреждения. Поэтому для серьёзного парсинга к Selenium почти всегда добавляют качественные прокси с ротацией, разумные задержки, прогретые профили с куками и имитацию человеческого поведения. И всё равно против защиты третьего поколения голого Selenium часто оказывается недостаточно.


Когда стоит брать Selenium, а когда — нет

Selenium оправдан, когда:

  • сайт целиком строится на JavaScript и без браузера контент не получить;
  • нужна имитация сложного пользовательского сценария (логин, многошаговые формы, бесконечный скролл);
  • объёмы умеренные, а не миллионы страниц в час;
  • у вас уже есть стек на Java/C#/Python и хочется остаться в нём.

Лучше поискать альтернативу, когда:

  • данные доступны через обычный HTTP/API — тогда requests/Scrapy/httpx будут в разы быстрее и дешевле;
  • нужен максимальный масштаб и скорость;
  • цель — обойти серьёзную антибот-защиту: здесь часто выигрывают Playwright или Puppeteer (более современные, с лучшим контролем над браузером и удобными stealth-плагинами), а иногда — nodriver или специализированные API.

Итог

Selenium — мощный и универсальный инструмент: он работает с динамическими сайтами, поддерживает множество языков и браузеров, имеет огромное комьюнити и отличную документацию. Это делает его хорошим выбором для парсинга сложных JS-страниц и сценариев, имитирующих реального пользователя.

Но у него есть две серьёзные платы: ресурсоёмкость (а значит, проблемы со скоростью и масштабированием) и лёгкая детектируемость. «Из коробки» Selenium оставляет десятки следов автоматизации, и хотя их можно частично замаскировать, против современной антибот-защиты этого нередко мало.

Практический вывод простой: если данные можно достать HTTP-запросом — берите HTTP-парсер. Если без браузера никак — Selenium отлично подойдёт, но закладывайте в проект прокси, ротацию, человеческое поведение и анти-детект, а для самых защищённых целей честно сравните его с Playwright, Puppeteer и более новыми решениями.