Selenium — это инструмент для автоматизации браузеров. Звучит сухо, но по сути это способ заставить браузер делать то, что обычно делает человек: кликать на кнопки, заполнять формы, проверять что там на странице появилось. Зачем? Потому что вручную прогонять одни и те же проверки после каждого обновления сайта — это ад для тестировщика.
Представьте: у вас интернет-магазин. После каждого релиза нужно проверить корзину, оформление заказа, авторизацию, поиск. Вручную это часа три минимум. С автотестами на Selenium — минут десять, и можно пойти кофе попить. Плюс тесты не устают, не ошибаются из-за невнимательности и работают круглосуточно.
Если вы хотите серьёзно погрузиться в тему, есть отличные курсы по автоматизации тестирования, где разбирают всё от основ до продвинутых техник. Но и самостоятельно разобраться можно, если есть желание.
Главное преимущество Selenium — кроссбраузерность. Пишешь тест один раз, запускаешь в Chrome, Firefox, Safari. Работает везде (ну, почти). Ещё один плюс — бесплатный и с открытым исходником. Не нужно платить за лицензии, можно крутить и на своём ноутбуке, и на сервере компании.
Selenium WebDriver — сердце системы
WebDriver — это программный интерфейс, который связывает ваш код с браузером. Вы пишете команды на Python (или другом языке), а WebDriver переводит их в действия браузера. Между вашим скриптом и браузером стоит драйвер — отдельная программа для каждого браузера.
ChromeDriver для Chrome. GeckoDriver для Firefox. EdgeDriver для Edge. Каждый из них понимает команды по стандарту W3C WebDriver и знает как заставить конкретный браузер выполнить нужное действие.
Архитектура простая: ваш Python-скрипт отправляет HTTP-запросы драйверу, драйвер управляет браузером, браузер возвращает результаты обратно. Всё это происходит быстро, хотя иногда бывают задержки… об этом позже поговорим.
Готовим окружение 🛠️
Первое — ставим Python. Если у вас уже стоит версия 3.8+, отлично. Если нет, качаем с официального сайта, устанавливаем, проверяем командой python --version.
Второе — устанавливаем сам Selenium. Открываем терминал и пишем:
pip install selenium
Готово. Библиотека установлена. Но это ещё не всё.
Третье — драйверы браузеров. Вот тут начинается веселье. Нужно скачать исполняемый файл драйвера под вашу операционку. ChromeDriver для Windows — это .exe файл, для Linux и Mac — просто исполняемый бинарник. Скачали? Отлично. Теперь нужно положить его туда, откуда система сможет его найти.
Самый простой способ — добавить путь к драйверу в переменную PATH. На Windows это делается через свойства системы. На Linux и Mac можно просто переместить драйвер в /usr/local/bin. Или указать путь явно в коде, но это менее удобно.
Про виртуальное окружение. Да, лучше создать. Команда python -m venv venv создаст отдельную папку для всех зависимостей проекта. Активируешь его, ставишь туда Selenium и другие библиотеки — и они не конфликтуют с другими проектами на твоём компьютере.
IDE и инструменты
PyCharm — хороший выбор. VS Code тоже норм, легче и быстрее. Ставишь расширения для Python, и всё работает из коробки. Автодополнение, подсветка синтаксиса, встроенный отладчик. Без этого писать код можно, но будет больно.
Первые шаги с WebDriver
Открываем любимый редактор, создаём файл test.py и пишем:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://google.com")
print(driver.title)
driver.quit()
Запускаем. Если всё настроено правильно, откроется окно Chrome, загрузится Google, в консоли выведется заголовок страницы, и браузер закроется. Вот и весь первый автотест 🎉
Метод get() открывает URL. title возвращает заголовок страницы. quit() закрывает браузер полностью, вместе со всеми вкладками. Есть ещё close(), но он закрывает только текущую вкладку.
Можно управлять размером окна. driver.maximize_window() развернёт его на весь экран. driver.set_window_size(1920, 1080) установит конкретные размеры. Полезно, если тестируешь адаптивную вёрстку.
Навигация: driver.back(), driver.forward(), driver.refresh(). Всё как в обычном браузере, только программно.
Ищем элементы на странице
Вот это уже интереснее. Чтобы кликнуть на кнопку или ввести текст в поле, нужно сначала найти этот элемент. Selenium предлагает несколько способов поиска:
- По ID — самый надёжный, если у элемента есть уникальный id
- По имени класса — class=»button-submit»
- По CSS-селектору — как в стилях, очень гибко
- По XPath — мощный, но может быть хрупким
- По тексту ссылки — для тегов <a>
- По имени тега — найти все <button> на странице
Пример:
from selenium.webdriver.common.by import By
element = driver.find_element(By.ID, "search-input")
element.send_keys("Selenium автотесты")
element.submit()
Тут мы нашли поле ввода по ID, ввели текст и отправили форму. Метод find_element возвращает первый найденный элемент. Если хочешь найти все совпадения, используй find_elements (с s на конце) — вернёт список.
XPath выглядит страшно, но иногда без него никуда. Например, нужно найти кнопку внутри конкретного div с определённым классом. CSS-селектор может не справиться, а XPath типа //div[@class='form-wrapper']//button решит проблему.
Что делать с найденными элементами
click() — кликнуть. send_keys("текст") — ввести текст. clear() — очистить поле ввода. Базовые операции, которые покрывают 80% сценариев.
Выпадающие списки требуют отдельного подхода. Для них есть класс Select:
from selenium.webdriver.support.ui import Select
dropdown = Select(driver.find_element(By.ID, "country"))
dropdown.select_by_visible_text("Россия")
Можно выбирать по значению, по индексу, по видимому тексту. Удобно.
Для сложных взаимодействий типа drag-and-drop или наведения мыши есть ActionChains. Создаёшь цепочку действий, а потом выполняешь их одной командой perform(). Выглядит примерно так:
from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(driver)
actions.move_to_element(element).click().perform()
Окна, фреймы, алерты
Бывает, что на сайте открывается новое окно или вкладка. Selenium по умолчанию остаётся в старом окне, нужно явно переключиться:
driver.switch_to.window(driver.window_handles[1])
window_handles — это список всех открытых окон. Первое окно — индекс 0, второе — индекс 1.
С iframe тоже нужно переключаться. Если элемент внутри iframe, просто так его не найдёшь:
driver.switch_to.frame("frame-name")
# теперь можно работать с элементами внутри
driver.switch_to.default_content() # вернуться обратно
JavaScript alert, confirm, prompt — всплывающие окна браузера. Их нельзя найти как обычные элементы, но можно обработать:
alert = driver.switch_to.alert
print(alert.text)
alert.accept() # нажать OK
# или alert.dismiss() для Cancel
Ожидания — боль и спасение
Вот честно, большинство проблем с нестабильными тестами из-за ожиданий. Страница загружается не моментально. Элементы появляются с задержкой. AJAX-запросы возвращают данные когда им вздумается. И если твой тест пытается кликнуть на кнопку, которой ещё нет на странице — привет, NoSuchElementException.
Неявные ожидания
Самый простой способ — включить неявное ожидание один раз в начале теста:
driver.implicitly_wait(10)
Теперь при каждом поиске элемента Selenium будет ждать до 10 секунд, пока элемент не появится в DOM. Удобно, но не всегда работает как надо. Если элемент в DOM есть, но ещё невидим или неактивен, неявное ожидание не поможет.
Явные ожидания
Явные ожидания — это когда ты говоришь: жди конкретное условие для конкретного элемента. Намного гибче:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, "submit-btn")))
Тут мы ждём, пока кнопка не станет кликабельной. Не просто появится в DOM, а именно станет доступна для клика. Есть куча других условий: видимость элемента, наличие текста, изменение атрибута.
Явные ожидания спасают от flaky tests — тестов, которые то проходят, то падают без явной причины. Используйте их. Всегда.
⚠️ Главное правило: никогда не используй time.sleep(5). Это зло. Тест будет тормозить на пять секунд даже если элемент появился через полсекунды. Плюс это ненадёжно — иногда пяти секунд не хватит.
Pytest для организации 📦
Когда тестов становится больше трёх, нужна структура. Pytest — стандарт для Python-тестирования. Устанавливается просто:
pip install pytest
Создаёшь файлы с именами вида test_*.py или *_test.py. Внутри пишешь функции с префиксом test_. Запускаешь командой pytest — и все тесты прогоняются автоматически.
Фикстуры — вот где настоящая магия. Это функции, которые выполняются перед тестами (setup) и после (teardown). Для Selenium фикстура обычно создаёт WebDriver перед тестом и закрывает его после:
import pytest
from selenium import webdriver
@pytest.fixture
def browser():
driver = webdriver.Chrome()
yield driver
driver.quit()
Теперь в каждом тесте просто указываешь browser как параметр:
def test_google_search(browser):
browser.get("https://google.com")
assert "Google" in browser.title
Pytest автоматически вызовет фикстуру, передаст драйвер в тест, а после выполнения закроет браузер. Красиво и чисто.
Маркировка и параметризация
Можно помечать тесты маркерами. Например, какие-то тесты — smoke, какие-то — regression:
@pytest.mark.smoke
def test_login(browser):
# тест авторизации
Потом запускаешь только smoke-тесты командой pytest -m smoke. Удобно для быстрых проверок перед релизом.
Параметризация позволяет запустить один тест с разными данными:
@pytest.mark.parametrize("query", ["Python", "Java", "JavaScript"])
def test_search(browser, query):
# тест выполнится три раза с разными запросами
Меньше дублирования кода, больше покрытие.
Page Object Model — порядок в хаосе
Когда тестов десятки, а то и сотни, начинается ад с поддержкой. Изменился локатор кнопки на сайте — нужно править во всех тестах. Добавили новое поле в форму — опять везде лезть. Page Object Model (POM) решает эту проблему.
Идея простая: создаёшь отдельный класс для каждой страницы сайта. В классе описываешь все элементы и действия с этой страницей. Тесты не работают напрямую с WebDriver и локаторами — они вызывают методы page objects.
Например, класс для страницы поиска:
class SearchPage:
def __init__(self, driver):
self.driver = driver
self.search_input = (By.NAME, "q")
self.search_button = (By.NAME, "btnK")
def search(self, query):
element = self.driver.find_element(*self.search_input)
element.send_keys(query)
self.driver.find_element(*self.search_button).click()
Теперь в тесте просто:
def test_search(browser):
page = SearchPage(browser)
page.search("Selenium")
# проверки
Локатор изменился? Правишь в одном месте — в классе страницы. Все тесты продолжают работать.
Обычно создают базовый класс BasePage с общими методами для всех страниц: ожидания, клики, поиск элементов. А конкретные страницы наследуются от него и добавляют специфичные методы.
💡 Структура проекта с POM:
- pages/ — классы страниц (base_page.py, main_page.py, search_page.py)
- tests/ — тестовые сценарии (test_search.py, test_login.py)
- conftest.py — общие фикстуры для всех тестов
Продвинутые фишки 🚀
JavaScript-магия
Иногда Selenium не может кликнуть на элемент. Он перекрыт другим элементом, или находится вне зоны видимости. В таких случаях можно выполнить JavaScript напрямую:
driver.execute_script("arguments[0].click();", element)
Прокрутка страницы тоже через JavaScript проще:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
Можно изменять DOM, читать переменные из JS, делать что угодно. Это мощный инструмент, но злоупотреблять не стоит — тесты должны имитировать поведение реального пользователя, а пользователи JavaScript не выполняют.
Скриншоты и отчёты
Когда тест падает, хочется увидеть что пошло не так. Скриншот помогает:
driver.save_screenshot("error.png")
Можно сделать скриншот автоматически при падении теста через фикстуру pytest. В conftest.py добавляешь хук:
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
if report.when == "call" and report.failed:
driver = item.funcargs['browser']
driver.save_screenshot(f"{item.name}.png")
HTML-отчёты генерятся плагином pytest-html:
pip install pytest-html
pytest --html=report.html
Получаешь красивый отчёт с результатами всех тестов, временем выполнения, логами.
Обход детекции автоматизации 🕵️
Многие сайты научились распознавать Selenium. Яндекс, например, может заблокировать или показать капчу. Проблема в том, что браузер, управляемый Selenium, имеет определённые маркеры: свойство navigator.webdriver равно true, отсутствуют некоторые плагины.
Есть способы обойти:
- Использовать библиотеку undetected-chromedriver — патченная версия ChromeDriver
- Настроить опции для эмуляции реального пользователя
- Добавить случайные задержки между действиями
- Эмулировать движение мыши и прокрутку
Пример с опциями:
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
Это не панацея, но помогает в большинстве случаев.
❓ Частые вопросы про Selenium автотесты
Q Какой язык программирования лучше выбрать для Selenium?
Python — наиболее популярный выбор из-за простого синтаксиса и быстрого старта. Java используют в крупных enterprise-проектах, где уже есть Java-разработчики. JavaScript подходит для фронтенд-команд, работающих с Node.js. C# выбирают компании с .NET-стеком. Для обучения и большинства задач рекомендую Python — меньше кода, больше готовых библиотек, активное комьюнити.
Q Можно ли использовать Selenium для мобильных приложений?
Selenium предназначен только для веб-приложений в браузерах. Для мобильных нативных приложений существует Appium — он построен на архитектуре WebDriver, но работает с iOS и Android приложениями. Если тестируете мобильную версию сайта в браузере — Selenium справится, можно даже эмулировать мобильные устройства через Chrome DevTools Protocol.
Q Почему мои тесты работают нестабильно?
Основная причина — неправильные ожидания. Замените все time.sleep() на явные ожидания WebDriverWait. Вторая причина — хрупкие локаторы типа XPath с индексами элементов. Используйте уникальные ID или data-атрибуты. Третья — гонка условий при параллельном запуске тестов на общих данных. Четвертая — нестабильность тестовой среды или самого сайта. Проверьте логи, добавьте скриншоты при падении, анализируйте паттерны ошибок.
Q Как ускорить выполнение Selenium тестов?
Запускайте тесты параллельно через pytest-xdist (команда pytest -n 4 для 4 потоков). Используйте headless режим браузера — без GUI тесты работают быстрее. Настройте Selenium Grid для распределения тестов между несколькими машинами. Отключите загрузку изображений и CSS через опции браузера, если они не критичны для тестов. Оптимизируйте сами тесты — убирайте лишние ожидания, объединяйте проверки где возможно.
Q Нужно ли знать JavaScript для работы с Selenium?
Базовые знания JavaScript полезны, но не обязательны для начала. Selenium предоставляет методы для большинства операций без JS. Продвинутые сценарии иногда требуют execute_script — тогда понимание JS поможет. Достаточно знать основы: как получить элемент, изменить его свойства, выполнить клик. Учите по мере необходимости — когда стандартных методов Selenium недостаточно.
Q Как тестировать приложения с двухфакторной аутентификацией?
Несколько подходов. Первый — договориться с разработчиками о тестовом окружении, где 2FA отключена или есть универсальный код. Второй — использовать cookies или токены авторизации напрямую через driver.add_cookie(), минуя форму логина. Третий — интегрироваться с API для получения кодов 2FA программно. Четвертый — использовать библиотеки типа pyotp для генерации TOTP-кодов из secret key.
Q Selenium или Playwright — что выбрать в 2025-26 году?
Selenium остается стандартом индустрии с огромным комьюнити и поддержкой всех браузеров. Playwright — современная альтернатива от Microsoft, быстрее работает, лучше с асинхронными операциями, встроенные ожидания умнее. Для новых проектов с modern stack рекомендую Playwright. Для существующих систем, интеграции с legacy или если команда уже знает Selenium — оставайтесь на нём. Оба инструмента отлично решают задачи автоматизации.