Автоматизация браузера с Selenium: примеры и инструкции

Раздел: Библиотеки -> Библиотеки для автоматизации браузера

Основные возможности Selenium и их применение

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

Для установки библиотеки Selenium используется pip. Команда: pip install selenium. Рекомендуется также установить менеджер драйверов webdriver-manager для автоматической загрузки драйвера браузера.


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

service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.get('https://www.example.com')
print(driver.title)  # Example Domain
driver.quit()

Selenium python библиотека (библиотека selenium в python)

Альтернатива -- указать путь к драйверу вручную или использовать другой браузер:


# Firefox
from selenium.webdriver.firefox.service import Service as FirefoxService
from webdriver_manager.firefox import GeckoDriverManager
service = FirefoxService(GeckoDriverManager().install())
driver = webdriver.Firefox(service=service)

# Edge
from selenium.webdriver.edge.service import Service as EdgeService
from webdriver_manager.microsoft import EdgeChromiumDriverManager
service = EdgeService(EdgeChromiumDriverManager().install())
driver = webdriver.Edge(service=service)

Ошибка WebDriverException: 'chromedriver' executable needs to be in PATH возникает, когда драйвер не найден. Решение -- использовать webdriver-manager или добавить папку с драйвером в системную переменную PATH. Также возможна ошибка ModuleNotFoundError: No module named 'selenium' -- проверьте установку через pip list | grep selenium.

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

Основной метод поиска одного элемента -- find_element(By.ID, 'id_value'). Он возвращает первый подходящий объект WebElement.


from selenium.webdriver.common.by import By

element = driver.find_element(By.ID, 'main-content')
print(element.text)

Доступны и другие стратегии локации:


# По классу
driver.find_element(By.CLASS_NAME, 'container')
# По имени тега
driver.find_element(By.TAG_NAME, 'h1')
# По XPath
driver.find_element(By.XPATH, '//div[@id="content"]/p[1]')
# По CSS-селектору
driver.find_element(By.CSS_SELECTOR, 'div#content > p:first-child')
# По тексту ссылки
driver.find_element(By.LINK_TEXT, 'Подробнее')
# По частичному тексту ссылки
driver.find_element(By.PARTIAL_LINK_TEXT, 'Подроб')

Для получения списка элементов используется find_elements (возвращает список).

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

Как дождаться появления элемента?

Явные ожидания с помощью 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-element')))

Менее предпочтительные варианты:


# Неявное ожидание (глобальное)
driver.implicitly_wait(5)
element = driver.find_element(By.ID, 'slow-element')
# Принудительная задержка (не рекомендуется)
import time
time.sleep(3)

Также можно использовать FluentWait для гибкого задания таймаута и игнорирования исключений.

Ошибка TimeoutException -- элемент не появился за отведённое время. Проверьте локатор и время загрузки. Не используйте time.sleep в продакшне, так как это замедляет тесты и не гарантирует точного ожидания.

Как выполнить JavaScript на странице?

Метод driver.execute_script() выполняет JavaScript в контексте текущей страницы.


title = driver.execute_script('return document.title;')
print(title)

Передача аргументов в скрипт:


# Прокрутить к элементу
driver.execute_script('arguments[0].scrollIntoView();', element)
# Изменить атрибут
driver.execute_script('arguments[0].setAttribute("style", "border:2px solid red");', element)
# Асинхронное выполнение
driver.execute_async_script('var callback = arguments[arguments.length - 1]; setTimeout(() => callback("done"), 2000);')

Ошибка JavascriptException -- синтаксическая ошибка в скрипте или попытка доступа к несуществующему объекту. Возвращаемые сложные объекты могут быть сериализованы не полностью.

Как сделать скриншот страницы или элемента?

Снимок всей страницы сохраняется с помощью driver.save_screenshot().


driver.save_screenshot('full_page.png')

Скриншот отдельного элемента:


element = driver.find_element(By.ID, 'logo')
element.screenshot('element.png')

Получение изображения в формате PNG (base64):


png_data = driver.get_screenshot_as_base64()
with open('page.png', 'wb') as f:
    import base64
    f.write(base64.b64decode(png_data))

Проблемы могут возникнуть при снятии скриншота элемента, который не виден на экране -- предварительно прокрутите к нему с помощью execute_script. Ошибка записи файла возникает при отсутствии прав на запись в директорию.

Как работать с выпадающими списками (select)?

Для тега <select> используется класс Select из модуля selenium.webdriver.support.ui.


from selenium.webdriver.support.ui import Select

select_element = driver.find_element(By.NAME, 'options')
select = Select(select_element)
select.select_by_visible_text('Option 2')
print(select.first_selected_option.text)

Другие способы выбора:


select.select_by_value('opt2')   # по значению атрибута value
select.select_by_index(1)        # по порядковому индексу (0-based)
# Для мультиселекта:
select.deselect_all()
select.select_by_visible_text('Option 3')

Если элемент не является <select>, возникает NotImplementedError. В таких случаях нужно использовать обычные клики по пунктам меню. Также возможна ошибка NoSuchElementException при неверном значении.

Как выполнять сложные действия мыши и клавиатуры?

Класс ActionChains позволяет строить цепочки действий.


from selenium.webdriver.common.action_chains import ActionChains

actions = ActionChains(driver)
actions.move_to_element(element)
actions.click()
actions.perform()

Другие действия:


# Контекстное меню (правая кнопка)
actions.context_click(element).perform()
# Двойной клик
actions.double_click(element).perform()
# Перетаскивание
drag_source = driver.find_element(By.ID, 'drag')
target = driver.find_element(By.ID, 'drop')
actions.drag_and_drop(drag_source, target).perform()
# Нажатие и удержание клавиши
actions.key_down(Keys.SHIFT).send_keys('hello').key_up(Keys.SHIFT).perform()

Действия могут не сработать, если элемент не видим или перекрыт другим. Используйте move_to_element и прокрутку. Ошибка MoveTargetOutOfBoundsException -- элемент находится за пределами видимой области.

Работа с iframe

Для взаимодействия с элементами внутри iframe необходимо переключить контекст на него.

Пример

# Переключение по имени или id
driver.switch_to.frame('iframe-name')
# Или по WebElement
iframe = driver.find_element(By.CSS_SELECTOR, 'iframe')
driver.switch_to.frame(iframe)

# Теперь можно искать элементы внутри iframe
inner_element = driver.find_element(By.ID, 'inside-iframe')
print(inner_element.text)

# Вернуться к основному содержимому
driver.switch_to.default_content()
Вывод: текст элемента внутри iframe, например "Это содержимое iframe".

Настройка опций браузера (headless, прокси, user-agent)

Через класс Options можно конфигурировать запуск браузера.

Пример

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--headless=new')  # безголовый режим
options.add_argument('--proxy-server=http://proxy:8080')  # прокси
options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
options.add_experimental_option('excludeSwitches', ['enable-logging'])  # скрыть логи

driver = webdriver.Chrome(options=options)
driver.get('https://httpbin.org/headers')
print(driver.page_source)
driver.quit()
В исходном коде страницы виден переданный User-Agent и IP прокси.

Обработка всплывающих окон и алертов

Алерты (диалоговые окна) можно перехватить и взаимодействовать с ними.

Пример

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

# Нажимаем кнопку, вызывающую alert
driver.find_element(By.ID, 'alert-btn').click()

# Ждём появления алерта
alert = WebDriverWait(driver, 5).until(EC.alert_is_present())
print(alert.text)  # 'Вы уверены?'
alert.accept()  # принять
alert.dismiss() # отклонить (если нужно)
# Для ввода текста в prompt:
alert.send_keys('Ответ')
alert.accept()
Вывод: 'Вы уверены?'. После accept окно закрывается.

Загрузка файлов с помощью Selenium

Для загрузки файла обычно используется элемент input[type=file], в который отправляется путь к файлу через send_keys.

Пример

from pathlib import Path

upload_input = driver.find_element(By.CSS_SELECTOR, 'input[type="file"]')
file_path = str(Path.cwd() / 'example.txt')
upload_input.send_keys(file_path)

# Дождаться завершения загрузки
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, 'upload-success')))
print('Файл загружен')
В консоль выводится 'Файл загружен' после появления индикатора успеха.

Параллельный запуск браузеров с ThreadPoolExecutor

Для ускорения тестов можно запускать несколько экземпляров браузера параллельно.

Пример

from concurrent.futures import ThreadPoolExecutor
from selenium import webdriver
from selenium.webdriver.chrome.service import Service

def open_and_get_title(url):
    service = Service()  # предполагается, что chromedriver в PATH
    driver = webdriver.Chrome(service=service)
    driver.get(url)
    title = driver.title
    print(f'{url}: {title}')
    driver.quit()
    return title

urls = ['https://www.example.com', 'https://www.google.com', 'https://www.python.org']
with ThreadPoolExecutor(max_workers=3) as executor:
    results = executor.map(open_and_get_title, urls)
print(list(results))
Вывод в консоль:
https://www.example.com: Example Domain
https://www.google.com: Google
https://www.python.org: Welcome to Python.org
['Example Domain', 'Google', 'Welcome to Python.org']

Использование Selenium Grid для распределенного тестирования

Selenium Grid позволяет запускать тесты на удалённых машинах и в разных браузерах одновременно.

Пример

# Настройка удалённого драйвера
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

capabilities = DesiredCapabilities.CHROME.copy()
driver = webdriver.Remote(
    command_executor='http://localhost:4444/wd/hub',
    options=webdriver.ChromeOptions()
)
driver.get('https://www.selenium.dev')
print(driver.title)
driver.quit()
Вывод: 'Selenium'. Тест выполнен на удалённом узле Grid, что видно в логах хаба.

Библиотека Selenium в Python - comments

En
Selenium python библиотека (python)