Selenium — это инструмент для автоматизации браузера, изначально созданный для тестирования веб-приложений. Но за счёт того, что он управляет настоящим браузером, его давно и активно используют для парсинга сайтов, особенно тех, которые отдают контент через JavaScript и не открываются простым HTTP-запросом.
В этой статье разберём, как Selenium устроен, как с ним работать на разных языках, в чём его сильные и слабые стороны и почему он легко детектируется системами антибот-защиты.
Если вы только выбираете подход к парсингу, начните с наших обзоров «На каком языке писать парсер? Обзор основных решений» и «Библиотеки для парсинга сайтов» — там мы сравниваем инструменты на верхнем уровне. Эта статья — углублённый разбор одного из них.
Что такое Selenium и как он работает
Selenium управляет браузером не «изнутри», а через отдельный драйвер по протоколу WebDriver (стандарт W3C). Схема всегда одна и та же:
Ваш скрипт ──▶ 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 для постобработки) и масса готовых примеров.
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-командах.
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) хорошо ложится на ожидание загрузки элементов.
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.
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
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.SeleniumBaseUC 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 и более новыми решениями.