Selenium WebDriver: установка и устройство
Собираем рабочее окружение и заодно понимаем, что происходит между строчкой driver.get(...) и реально открывшимся браузером — без этой картинки половина ошибок Selenium выглядит мистикой.
Selenium WebDriver — это библиотека и стандартизированный протокол, позволяющие управлять настоящим браузером извне: не эмуляция, а тот же Chrome или Firefox, который стоит у пользователя, только команды ему шлёт ваш код.
Слово «настоящий» здесь принципиально. Selenium не рисует свою страницу и не парсит HTML, как requests с BeautifulSoup. Он открывает браузер, и браузер честно выполняет JavaScript, применяет CSS, шлёт запросы, рендерит DOM. Поэтому Selenium видит ровно то, что видит пользователь, — и поэтому он медленный. Обе эти черты растут из одного корня.
Как WebDriver управляет браузером
Между вашим скриптом и браузером стоит посредник — драйвер: отдельная программа (chromedriver, geckodriver, msedgedriver), которую пишут авторы самого браузера. Цепочка выглядит так:
ваш скрипт на Python
│ вызов метода: driver.get("https://example.com")
▼
библиотека selenium
│ HTTP-запрос с JSON-телом на localhost
▼
драйвер (chromedriver) — маленький HTTP-сервер
│ внутренний протокол браузера (у Chrome — CDP)
▼
браузер Chrome — открывает страницу
Самое неожиданное для новичков: Selenium общается с драйвером по обычному HTTP. Драйвер — это локальный веб-сервер, который слушает порт (например, 9515) и принимает REST-подобные команды. Набор этих команд стандартизирован W3C и называется WebDriver Protocol. Именно благодаря стандарту один и тот же код работает и с Chrome, и с Firefox: меняется драйвер, но не команды.
Вот как выглядит то, что библиотека шлёт под капотом, когда вы пишете driver.get("https://example.com"):
POST http://localhost:9515/session/8f3c.../url
Content-Type: application/json
{"url": "https://example.com"}
Ответ:
{"value": null} # null = команда выполнена без ошибок
Основные команды протокола — их полезно узнавать в трейсах и логах:
| Запрос | Метод Python | Что делает |
POST /session | webdriver.Chrome() | запускает браузер, создаёт сессию, возвращает её id |
POST /session/{id}/url | driver.get(url) | переходит по адресу |
GET /session/{id}/title | driver.title | возвращает заголовок вкладки |
POST /session/{id}/element | driver.find_element(...) | ищет элемент, возвращает его ссылку |
POST /session/{id}/element/{eid}/click | element.click() | кликает по элементу |
DELETE /session/{id} | driver.quit() | закрывает сессию и браузер |
Из этой картинки сразу следуют три практических вывода. Первый: каждая строчка вашего теста — это сетевой round-trip, поэтому UI-тесты медленные, и поэтому не надо дёргать find_element в цикле по сто раз. Второй: сессия — это состояние на стороне драйвера; если процесс Python умрёт, не закрыв сессию, браузер останется висеть в памяти. Третий: версия драйвера обязана понимать версию браузера — драйвер разговаривает с Chrome по внутреннему протоколу, который меняется от версии к версии.
Установка
Нужны три вещи: Python 3.8+, сам браузер (Chrome или Firefox — обычный, тот же, что для сёрфинга) и библиотека selenium.
# 1. Отдельное виртуальное окружение под проект — обязательно, а не «когда-нибудь потом»
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# 2. Библиотека. Пакет называется просто selenium
pip install selenium
# 3. Проверяем, что встало
pip show selenium | head -2
Результат:
Name: selenium
Version: 4.27.1
Обратите внимание на две ловушки в имени пакета. Пакет для Python называется selenium — не selenium-webdriver (это npm-пакет для JavaScript) и не seleniumbase (это отдельный сторонний фреймворк поверх Selenium). И версия должна быть 4.x: между Selenium 3 и 4 сменился синтаксис поиска элементов, и половина статей в интернете написана про третью версию, отчего у новичков всё «не работает».
Selenium Manager: почему драйвер больше не надо качать руками
Раньше установка выглядела так: узнать версию Chrome, пойти на сайт, скачать chromedriver точно такой же версии, положить его в PATH, повторять после каждого автообновления Chrome. Именно на этом шаге отваливалась половина начинающих.
Начиная с Selenium 4.6 в библиотеку встроен Selenium Manager — он делает всё это за вас. При первом создании драйвера Selenium Manager:
- определяет, какой браузер и какой версии установлен в системе;
- подбирает совместимую версию драйвера;
- скачивает её (а при необходимости — и сам браузер) и кладёт в локальный кэш;
- подставляет путь к драйверу в вашу сессию.
Кэш лежит в ~/.cache/selenium (Linux/macOS) или %USERPROFILE%\.cache\selenium (Windows). Скачивание происходит один раз: дальше драйвер берётся из кэша, пока Chrome не обновится.
Практический вывод: вам больше не нужны ни ручное скачивание, ни пакет webdriver-manager (сторонняя библиотека, которая решала эту проблему до 4.6 — в новых проектах она лишняя). Строчка создания драйвера теперь выглядит просто:
from selenium import webdriver
driver = webdriver.Chrome() # Selenium Manager сам найдёт и подложит chromedriver
driver.quit()
Проверка окружения
Прежде чем писать первый тест, полезно убедиться, что вся цепочка «Python → selenium → драйвер → браузер» жива. Вот скрипт-диагностика: он ничего не тестирует, он проверяет вас.
import platform
import selenium
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
print("Python :", platform.python_version())
print("Selenium:", selenium.__version__)
options = Options()
options.add_argument("--headless=new") # без окна: быстрее и работает на сервере
driver = webdriver.Chrome(options=options)
try:
caps = driver.capabilities
print("Браузер:", caps["browserName"], caps["browserVersion"])
print("Драйвер:", caps["chrome"]["chromedriverVersion"].split(" ")[0])
driver.get("https://example.com")
print("Заголовок:", driver.title)
finally:
driver.quit()
print("Окружение готово.")
Результат (числа версий будут вашими):
Python : 3.12.3
Selenium: 4.27.1
Браузер: chrome 131.0.6778.86
Драйвер: 131.0.6778.85
Заголовок: Example Domain
Окружение готово.
Разберём небанальные места. driver.capabilities — это словарь, который драйвер вернул в ответ на POST /session: там лежат реальные версии браузера и драйвера, и это первое, что стоит распечатать, когда «у меня не работает, а у коллеги работает». Флаг --headless=new запускает Chrome без графического окна — это новая реализация headless-режима (старая, --headless, вела себя иначе и местами ломала тесты). А try/finally вокруг работы с драйвером — привычка, которую надо выработать с первого дня: о ней подробно в следующем уроке.
Как это работает
Что физически происходит в момент webdriver.Chrome():
- Selenium Manager сверяется с кэшем, при необходимости качает
chromedriver; - библиотека запускает процесс
chromedriverи передаёт ему свободный порт; chromedriverподнимается как локальный HTTP-сервер и запускает процесс Chrome — со свежим временным профилем, без ваших закладок, расширений и куки (поэтому автотест всегда стартует «с чистого листа», и это правильно);- библиотека шлёт
POST /session, драйвер отвечаетsessionId; - дальше каждая команда вашего теста превращается в HTTP-запрос с этим
sessionId.
После quit() происходит обратное: DELETE /session/{id}, драйвер закрывает Chrome, затем завершается сам. Если этого не случилось — в системе остаются два висящих процесса. На локальной машине это «просто памяти жалко», в CI-агенте после сотни таких прогонов кончается память и падают все тесты подряд.
Частые ошибки
SessionNotCreatedException: This version of ChromeDriver only supports Chrome version 128. Классика: Chrome обновился, а драйвер остался старый. На Selenium 4.6+ обычно означает, что вPATHлежит старый chromedriver, скачанный руками, и он перебивает Selenium Manager. Лечение: удалить его изPATHи дать менеджеру сделать свою работу.WebDriverException: unable to obtain driver / cannot find Chrome binary. Chrome вообще не установлен (частый случай на голом Linux-сервере) либо стоит в нестандартной папке. Ставим браузер или указываем путь:options.binary_location = "/usr/bin/google-chrome".- Корпоративный прокси и офлайн-машина. Selenium Manager лезет в интернет за драйвером. Если сеть закрыта — он падает на первом же запуске. Решения: положить драйвер заранее и передать путь через
Service(executable_path=...), либо прогреть кэш на машине с интернетом. - Установили не тот пакет.
pip install selenium-webdriverилиseleniumbaseвместоselenium, дальше —ImportErrorи час недоумения. - Копируете код из статьи 2019 года. Если видите
driver.find_element_by_id("x")илиwebdriver.Chrome("./chromedriver")— это Selenium 3, в четвёртой версии этих вызовов больше нет. Ищите синтаксис сByиService. - Ставите selenium глобально. Через полгода на машине четыре проекта с разными версиями и конфликт зависимостей.
venv— не формальность.
Итоги
- Selenium управляет настоящим браузером через посредника-драйвер; общение идёт по HTTP+JSON по стандарту W3C WebDriver Protocol.
- Каждая команда теста — сетевой round-trip к локальному серверу драйвера. Отсюда и медленность UI-тестов, и требование закрывать сессию.
- Установка сводится к
python -m venv+pip install selenium(версия 4.x). Браузер — обычный, установленный в системе. - Selenium Manager (с 4.6) сам качает и подкладывает драйвер. Руками
chromedriverскачивать не нужно,webdriver-manager— не нужен. - Первое, что печатают при проблемах, —
selenium.__version__иdriver.capabilities: там видно реальные версии браузера и драйвера.