Selenium на Python: автоматизация браузера
Python Selenium 4: установка без ручного скачивания драйвера, find_element и By, клики и ввод текста, ожидания WebDriverWait, headless, скриншоты и ошибки.
Содержание · 11 разделов
- Установка Selenium
- Драйвер скачивать не нужно: Selenium Manager
- Открыть страницу и закрыть браузер
- Поиск элементов: find_element и By
- Действия с элементами: клик, ввод текста, атрибуты
- Явные ожидания: WebDriverWait
- Headless-режим: браузер без окна
- Скриншоты
- Selenium или requests: что выбрать
- Частые ошибки
- NoSuchElementException: Unable to locate element
- TimeoutException
- ElementClickInterceptedException
- StaleElementReferenceException
- AttributeError: ‘WebDriver’ object has no attribute ‘find_element_by_id’
- TypeError: got an unexpected keyword argument ‘executable_path’
- SessionNotCreatedException
- ModuleNotFoundError: No module named ‘selenium’
- Частые вопросы
- Как выбрать пункт в выпадающем списке?
- Как загрузить файл через форму?
- Как сохранить cookies и не входить в аккаунт каждый раз?
- Как переключиться на новую вкладку?
- Как запустить браузер через прокси?
- Итог
Selenium управляет настоящим браузером из кода: открывает страницы, нажимает кнопки, заполняет формы, ждёт загрузки контента и делает скриншоты. Связку Python Selenium используют для автотестов веб-интерфейсов и для работы с сайтами, где данные подгружаются JavaScript. Минимальный пример:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome() # драйвер браузера Selenium скачает сам
driver.get("https://www.selenium.dev/selenium/web/web-form.html")
print(driver.title) # → Web form
driver.find_element(By.NAME, "my-text").send_keys("Selenium")
driver.find_element(By.CSS_SELECTOR, "button").click()
driver.quit()
Ниже — установка, поиск элементов, действия, ожидания, headless-режим, скриншоты и частые ошибки. Примеры проверены на Selenium 4.50, Python 3.12, Chrome и Edge в Windows; для экспериментов используется официальная тестовая страница проекта Selenium.
Установка Selenium
Поставьте пакет в виртуальное окружение:
# Windows
py -m pip install selenium
# macOS / Linux
python3 -m pip install selenium
Нужен Python 3.10 или новее (требование актуальных версий пакета). Обычно Selenium управляет уже установленным браузером: Chrome, Edge, Firefox или Safari. Если Chrome или Firefox на компьютере нет, Selenium Manager (начиная с версии 4.11) скачает браузер сам — для Chrome это сборка Chrome for Testing.
Драйвер скачивать не нужно: Selenium Manager
Браузером Selenium управляет через отдельную программу-драйвер: chromedriver для Chrome, msedgedriver для Edge, geckodriver для Firefox. Раньше драйвер нужно было скачивать вручную и следить, чтобы его версия совпадала с версией браузера.
Начиная с Selenium 4.6 в пакет встроен Selenium Manager. При вызове webdriver.Chrome() он сам определяет версию установленного браузера, скачивает подходящий драйвер и кеширует его в папке .cache/selenium в домашнем каталоге пользователя. Поэтому старые инструкции со скачиванием chromedriver.exe и прописыванием пути больше не нужны — первый запуск просто занимает чуть дольше, а для него требуется доступ в интернет.
Для других браузеров меняется только класс:
driver = webdriver.Chrome()
driver = webdriver.Edge()
driver = webdriver.Firefox()
driver = webdriver.Safari() # только macOS, нужно включить удалённое управление в Safari
Открыть страницу и закрыть браузер
from selenium import webdriver
driver = webdriver.Chrome()
try:
driver.get("https://www.selenium.dev/selenium/web/web-form.html")
print(driver.title) # → Web form
print(driver.current_url) # адрес текущей страницы
finally:
driver.quit() # закрыть браузер и драйвер
driver.get() ждёт окончания загрузки страницы (события load), но не ждёт контента, который скрипты подгружают позже, — об этом ниже, в разделе про ожидания.
Всегда вызывайте driver.quit(), лучше в блоке finally: иначе при ошибке в фоне останутся процессы браузера и драйвера. Метод close() закрывает только текущую вкладку. Про try/finally подробнее — в статье о try-except.
Поиск элементов: find_element и By
В Selenium 4 элементы ищут двумя методами с классом By:
driver.find_element(By..., "...")— первый подходящий элемент; если его нет — исключениеNoSuchElementException;driver.find_elements(By..., "...")— список всех подходящих элементов; если их нет — пустой список.
from selenium.webdriver.common.by import By
driver.find_element(By.ID, "my-text-id")
driver.find_element(By.NAME, "my-text")
driver.find_element(By.CSS_SELECTOR, "form button[type='submit']")
driver.find_element(By.XPATH, "//button[text()='Submit']")
driver.find_element(By.LINK_TEXT, "Return to index")
links = driver.find_elements(By.TAG_NAME, "a")
print(len(links))
| Стратегия | Что ищет |
|---|---|
By.ID | атрибут id |
By.NAME | атрибут name (поля форм) |
By.CLASS_NAME | один CSS-класс |
By.CSS_SELECTOR | любой CSS-селектор |
By.XPATH | выражение XPath |
By.TAG_NAME | имя тега: a, input, h1 |
By.LINK_TEXT | ссылку по точному тексту |
By.PARTIAL_LINK_TEXT | ссылку по части текста |
На практике чаще всего хватает By.ID и By.CSS_SELECTOR. Искать можно и внутри найденного элемента: form.find_element(By.TAG_NAME, "button").
Важно: методы вида
find_element_by_id()иfind_element_by_css_selector()из Selenium 3 удалены. Если в старом примере они встречаются, замените их наfind_element(By.ID, ...)иfind_element(By.CSS_SELECTOR, ...).
Действия с элементами: клик, ввод текста, атрибуты
from selenium.webdriver.common.keys import Keys
field = driver.find_element(By.NAME, "my-text")
field.clear() # очистить поле
field.send_keys("Selenium") # ввести текст
field.send_keys(Keys.ENTER) # нажать Enter
button = driver.find_element(By.CSS_SELECTOR, "button")
button.click()
Что можно прочитать у элемента:
| Свойство / метод | Что возвращает |
|---|---|
el.text | видимый текст элемента |
el.get_attribute("href") | значение атрибута или свойства (value, href…) |
el.tag_name | имя тега |
el.is_displayed() | виден ли элемент |
el.is_enabled() | доступен ли (не disabled) |
el.is_selected() | отмечен ли чекбокс или пункт списка |
Для произвольного JavaScript есть driver.execute_script() — например, прокрутка страницы вниз: driver.execute_script("window.scrollTo(0, document.body.scrollHeight)").
Явные ожидания: WebDriverWait
Главная причина нестабильных скриптов — попытка найти элемент, который ещё не появился. Решение — явное ожидание: ждать конкретного условия, но не дольше заданного времени. Полный рабочий пример на тестовой форме:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
driver = webdriver.Chrome()
try:
driver.get("https://www.selenium.dev/selenium/web/web-form.html")
driver.find_element(By.NAME, "my-text").send_keys("Selenium")
driver.find_element(By.CSS_SELECTOR, "button").click()
message = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.ID, "message"))
)
print(message.text) # → Received!
finally:
driver.quit()
WebDriverWait(driver, 10) проверяет условие каждые полсекунды. Как только оно выполнилось, until() возвращает результат (здесь — найденный элемент). Если за 10 секунд условие так и не выполнилось, будет TimeoutException. Обратите внимание: локатор передаётся кортежем (By.ID, "message").
Полезные условия из expected_conditions:
| Условие | Ждёт, пока… |
|---|---|
presence_of_element_located(loc) | элемент появится в DOM (может быть невидим) |
visibility_of_element_located(loc) | элемент появится и станет видимым |
element_to_be_clickable(loc) | элемент станет видимым и доступным для клика |
presence_of_all_elements_located(loc) | появится хотя бы один элемент; вернёт список |
invisibility_of_element_located(loc) | элемент исчезнет (например, спиннер) |
text_to_be_present_in_element(loc, text) | в элементе появится текст |
title_contains(text) / url_contains(text) | заголовок или URL будет содержать текст |
Есть ещё неявное ожидание driver.implicitly_wait(5): оно применяется ко всем вызовам find_element. Смешивать неявные и явные ожидания не стоит: время ожидания становится непредсказуемым. Выберите явные. И не используйте time.sleep() для ожидания контента: на быстрой сети он тратит время зря, а на медленной всё равно не спасает.
Headless-режим: браузер без окна
На сервере или в CI окна браузера не нужно. Включите headless-режим через опции:
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--window-size=1280,800")
driver = webdriver.Chrome(options=options)
Для Edge то же самое делается через webdriver.EdgeOptions(), для Firefox — webdriver.FirefoxOptions() с аргументом -headless. Размер окна в headless-режиме задавайте явно: от него зависит вёрстка страницы и то, какие элементы окажутся видимыми.
Скриншоты
driver.save_screenshot("page.png") # видимая область страницы, вернёт True при успехе
element = driver.find_element(By.TAG_NAME, "form")
element.screenshot("form.png") # только один элемент
Скриншоты удобно сохранять при падении теста, чтобы потом увидеть, что было на экране в момент ошибки.
Selenium или requests: что выбрать
Selenium запускает полноценный браузер, поэтому он медленный и требует ресурсов. Если нужные данные есть в HTML-коде страницы или сайт отдаёт их через API, быстрее и проще взять requests. Selenium нужен, когда:
- контент появляется только после выполнения JavaScript;
- нужно вести себя как пользователь: войти в аккаунт, нажимать кнопки, прокручивать;
- вы пишете автотесты интерфейса и проверяете, что видит человек в браузере.
Перед автоматизацией чужого сайта проверьте его правила использования и не создавайте избыточную нагрузку. Другие сценарии автоматизации рутины собраны в статье «Автоматизация на Python».
Частые ошибки
NoSuchElementException: Unable to locate element
Элемент не найден. Причины: он ещё не загрузился (используйте WebDriverWait), селектор неверен (проверьте его в инструментах разработчика браузера), элемент находится внутри iframe (сначала переключитесь: driver.switch_to.frame(...)), или он открыт в другой вкладке (driver.switch_to.window(...)).
TimeoutException
Условие ожидания не выполнилось за отведённое время. Проверьте локатор и само условие: например, visibility_of_element_located не дождётся элемента, который есть в DOM, но скрыт стилями.
ElementClickInterceptedException
Элемент найден, но клик перехватил другой элемент сверху: баннер cookies, всплывающее окно, фиксированная шапка. Дождитесь element_to_be_clickable, закройте перекрывающий элемент или прокрутите страницу к нужному месту.
StaleElementReferenceException
Вы нашли элемент, а потом страница перерисовала эту часть DOM, и ссылка «устарела». Найдите элемент заново после действия, которое меняет страницу.
AttributeError: ‘WebDriver’ object has no attribute ‘find_element_by_id’
Код написан для Selenium 3. Используйте find_element(By.ID, "...").
TypeError: got an unexpected keyword argument ‘executable_path’
Параметр executable_path удалён из Selenium 4. Обычно путь к драйверу вообще не нужен — его найдёт Selenium Manager. Если всё же нужен свой драйвер, передайте путь через Service:
from selenium.webdriver.chrome.service import Service
driver = webdriver.Chrome(service=Service(executable_path="путь/к/chromedriver"))
SessionNotCreatedException
Драйвер не смог запустить браузер. Частые причины: версия вручную указанного драйвера не совпадает с версией браузера; нет доступа в интернет при первом запуске, и Selenium Manager не смог скачать драйвер или браузер. Уберите ручной путь к драйверу и обновите пакет: pip install -U selenium.
ModuleNotFoundError: No module named ‘selenium’
Пакет установлен в другое окружение. Решение — в статье про ModuleNotFoundError.
Частые вопросы
Как выбрать пункт в выпадающем списке?
Для тега select есть вспомогательный класс Select:
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element(By.NAME, "my-select"))
select.select_by_visible_text("Two") # по тексту пункта
select.select_by_value("3") # по атрибуту value
print(select.first_selected_option.text)
Выпадающие списки, свёрстанные на div без select, открывают обычным click() и затем кликают по нужному пункту.
Как загрузить файл через форму?
Найдите поле input type="file" и передайте в send_keys() абсолютный путь к файлу — системное окно выбора файла при этом не открывается:
import os
driver.find_element(By.NAME, "my-file").send_keys(os.path.abspath("upload.txt"))
Как сохранить cookies и не входить в аккаунт каждый раз?
Сохраните cookies после входа в JSON, а при следующем запуске сначала откройте страницу того же сайта и только потом добавьте их — иначе будет InvalidCookieDomainException: invalid cookie domain:
import json
with open("cookies.json", "w") as f:
json.dump(driver.get_cookies(), f)
# при следующем запуске
driver.get("https://example.com/")
with open("cookies.json") as f:
for cookie in json.load(f):
driver.add_cookie(cookie)
driver.refresh()
Другой способ — запускать Chrome с отдельным профилем: options.add_argument("--user-data-dir=путь/к/профилю"). В профиле сохраняются cookies, localStorage и вход на сайты.
Как переключиться на новую вкладку?
Все открытые вкладки перечислены в driver.window_handles. Если ссылка открылась в новой вкладке, переключитесь на последнюю; новую пустую вкладку открывает switch_to.new_window():
driver.switch_to.window(driver.window_handles[-1]) # последняя открытая вкладка
driver.switch_to.new_window("tab") # новая вкладка
driver.get("https://www.selenium.dev/")
Перед закрытием вкладки через driver.close() переключитесь обратно, иначе следующие команды упадут с NoSuchWindowException.
Как запустить браузер через прокси?
Для Chrome и Edge прокси задаётся аргументом запуска:
options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://10.10.1.10:3128")
driver = webdriver.Chrome(options=options)
Логин и пароль в этом аргументе Chrome не принимает. Для прокси с авторизацией используют прокси без пароля с доступом по IP-адресу или отдельные инструменты, которые перехватывают запросы браузера.
Итог
Для работы с Selenium на Python достаточно pip install selenium и установленного браузера: драйвер скачает Selenium Manager. Элементы ищите через find_element(By..., ...), появления контента ждите через WebDriverWait с expected_conditions, на сервере включайте headless-режим и всегда закрывайте браузер через driver.quit(). Если браузер для задачи не обязателен, начните с requests; обзор других пакетов — в статье о библиотеках Python, полный справочник — в документации Selenium.
- #Python
- #Selenium
- #Автоматизация
- #Парсинг
- #Тестирование