Автоматизация браузера с Selenium WebDriver и Python

Раздел: Тестирование -> веб-автоматизация

Selenium WebDriver - один из самых популярных инструментов для автоматизации действий в веб-браузере. В сочетании с Python он позволяет писать тесты и скрипты, которые взаимодействуют с веб-страницами так же, как это делает живой пользователь: открывают страницы, заполняют формы, нажимают кнопки, извлекают данные.

Основы Selenium WebDriver в Python

Наиболее распространённый и эффективный способ начать работу - установить библиотеку selenium и использовать драйвер для конкретного браузера. Для Chrome нужен chromedriver, для Firefox - geckodriver. После установки создаётся экземпляр WebDriver, который управляет браузером.

Пример базового скрипта, который открывает страницу и извлекает заголовок:


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

driver = webdriver.Chrome()  # запуск Chrome
driver.get("https://example.com")
title = driver.find_element(By.TAG_NAME, "h1").text
print(title)
driver.quit()
    

Selenium webdriver python (selenium webdriver в python)

Этот код выполняет четыре шага: запуск браузера, переход по URL, поиск элемента h1 и вывод его текста, закрытие браузера. Все дальнейшие сценарии строятся вокруг таких базовых действий.

Как выбрать браузер и настроить его?

Можно использовать Chrome, Firefox, Edge, Safari. Для каждого требуется свой драйвер. Альтернатива - менеджер драйверов (например, webdriver-manager), который автоматически загружает и обновляет драйверы.


from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service

service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
    

Этот подход избавляет от ручного скачивания и указания пути к драйверу. Для Firefox используется GeckoDriverManager.

Как найти элемент на странице?

WebDriver предоставляет несколько стратегий поиска: по идентификатору (ID), имени класса (CLASS_NAME), имени тега (TAG_NAME), CSS-селектору (CSS_SELECTOR), XPath (XPATH). Лучше использовать надёжные селекторы - уникальные ID или атрибуты.


# Поиск по ID
elem = driver.find_element(By.ID, "submit-button")
# Поиск по классу
elem = driver.find_element(By.CLASS_NAME, "btn-primary")
# Поиск по XPath
elem = driver.find_element(By.XPATH, "//button[@type='submit']")
    

Каждый метод возвращает первый подходящий элемент. Если требуется несколько элементов, используется find_elements.

Типичная ошибка: NoSuchElementException возникает, когда элемент не найден. Причины: неправильный селектор, элемент ещё не загрузился, элемент находится в другом фрейме. Решение - проверить селектор, добавить ожидание (см. ниже) или переключиться на нужный фрейм.

Другая частая проблема: StaleElementReferenceException - элемент был найден, но после этого DOM изменился (например, обновилась страница). Тогда нужно найти элемент заново.

Как имитировать действия пользователя (клик, ввод текста)?

После поиска элемента можно вызвать его методы: click() - клик, send_keys() - ввод текста, clear() - очистка поля.


search_box = driver.find_element(By.NAME, "q")
search_box.clear()
search_box.send_keys("Selenium Python")
search_box.submit()  # отправка формы
    

Метод submit() удобен, когда нужно отправить форму, нажав Enter.

Ожидания и работа с динамическими элементами

Современные веб-приложения часто загружают контент асинхронно. Чтобы не ловить NoSuchElementException, применяются явные ожидания. Лучшая практика - использовать WebDriverWait с expected_conditions.


from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
element = wait.until(EC.presence_of_element_located((By.ID, "dynamic-content")))
    

Этот код ждёт до 10 секунд, пока элемент с ID dynamic-content не появится в DOM. После этого возвращает элемент, с которым можно работать.

Чем явные ожидания лучше неявных и time.sleep?

Неявное ожидание (implicitly_wait) задаётся один раз и применяется ко всем поискам элементов, но оно не умеет ждать конкретного состояния (например, кликабельности). Использование time.sleep() - плохая практика: оно останавливает выполнение на фиксированное время, даже если элемент загрузился раньше, что замедляет тесты.


# Неявное ожидание (менее гибкое)
driver.implicitly_wait(10)
element = driver.find_element(By.ID, "slow")
    

Явные ожидания гибко реагируют на состояние элемента. Возможные условия: visibility_of_element_located, element_to_be_clickable, presence_of_all_elements_located и другие.

Типичная ошибка: TimeoutException - элемент не появился за отведённое время. Причины: медленный сервер, неправильный селектор, элемент находится в iframe или внутри Shadow DOM. Решение - увеличить таймаут, проверить селектор, переключиться на iframe.

Важно: после переключения на iframe поиск элементов происходит внутри этого фрейма. Чтобы вернуться к основному документу, используется driver.switch_to.default_content().

Расширенные примеры работы с Selenium WebDriver

Ниже представлены более сложные сценарии, которые часто встречаются в реальных проектах автоматизации.

Работа с вкладками и окнами

Открыть новую вкладку, переключаться между ними, закрывать - всё это управляется через driver.switch_to.window.

Пример

# Открыть новую вкладку через JavaScript
driver.execute_script("window.open('https://example.com', '_blank');")
# Получить список всех окон
windows = driver.window_handles
# Переключиться на вторую вкладку
driver.switch_to.window(windows[1])
# Закрыть текущую вкладку
driver.close()
# Вернуться к первой
driver.switch_to.window(windows[0])
Результат: браузер открывает две вкладки, переключается, закрывает одну, возвращается.

Выполнение JavaScript

Иногда нужно выполнить произвольный JavaScript, например, изменить стиль элемента или прокрутить страницу.

Пример

# Скролл до элемента
driver.execute_script("arguments[0].scrollIntoView();", element)
# Получить текст через JS
text = driver.execute_script("return document.title;")
# Изменить атрибут
driver.execute_script("arguments[0].setAttribute('disabled', false);", button)

Скриншоты и снятие элементов

Selenium позволяет делать скриншоты всей страницы или отдельных элементов.

Пример

# Скриншот всей страницы
driver.save_screenshot("full_page.png")
# Скриншот элемента
with open("element.png", "wb") as f:
    f.write(element.screenshot_as_png)

Работа с файлами (загрузка)

Для загрузки файла используется send_keys() на элемент input с типом file.

Пример

file_input = driver.find_element(By.CSS_SELECTOR, "input[type='file']")
file_input.send_keys("/path/to/file.txt")

Обработка алертов

Модальные окна (alert, confirm, prompt) перехватываются через driver.switch_to.alert.

Пример

# Принять алерт
alert = driver.switch_to.alert
alert.accept()
# Отменить confirm
alert.dismiss()
# Ввести текст в prompt
alert.send_keys("Ответ")
alert.accept()

Кастомные ожидания (expected_conditions)

Можно создавать собственные условия, наследуя от ExpectedCondition.

Пример

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.remote.webdriver import WebDriver

def text_present_in_element_value(locator, value):
    def _predicate(driver: WebDriver):
        element = driver.find_element(*locator)
        return element.get_attribute("value") == value
    return _predicate

wait = WebDriverWait(driver, 10)
wait.until(text_present_in_element_value((By.ID, "input"), "Ожидаемое значение"))

Chrome Options и профили

Запуск браузера с особыми настройками (безголовый режим, отключение уведомлений, использование профиля пользователя).

Пример

from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--headless=new")  # безголовый режим
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1920,1080")
options.add_experimental_option("excludeSwitches", ["enable-automation"])

driver = webdriver.Chrome(options=options)

Логирование и отчёты

Для отладки полезно включить логирование от Selenium или использовать библиотеки типа allure для формирования отчётов.

Пример

import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

try:
    driver.get("https://example.com")
    logger.info("Страница загружена")
except Exception as e:
    logger.error(f"Ошибка: {e}")

selenium webdriver в python - comments

En
Selenium webdriver python (python)