Браузерные агенты (Playwright)
Уроки курсаБраузерные агенты (Playwright)
Введение в Playwright
Представьте, что вам нужно протестировать веб-приложение: зайти на сайт, заполнить форму, нажать кнопку, проверить результат. Делать это вручную каждый раз — утомительно и медленно. Или другая задача: собрать данные с сайта, который загружает контент через JavaScript. Обычные HTTP-запросы не помогут — нужен настоящий браузер.
Playwright — это библиотека для автоматизации браузеров, позволяющая управлять Chromium, Firefox и WebKit из Python. Как правило, её используют для автоматизации тестов веб-приложений, скрапинга данных и симуляции действий пользователя. Основное преимущество Playwright в том, что она поддерживает асинхронное выполнение, надежно работает с динамическими страницами и предоставляет мощные инструменты для работы с селекторами и ожиданиями.
Удобные функции этого фреймворка:
- Поддерживает Chromium, Firefox и WebKit — можно тестировать сайты под разными браузерами.
- Полностью работает с асинхронными страницами (SPA, динамический контент).
- Позволяет делать скриншоты и видео для диагностики тестов.
- Есть синхронное и асинхронное API, что удобно для разных сценариев.
Запуск браузера
Для начала работы с Playwright необходимо установить библиотеку. Это можно сделать с помощью команды:
pip install playwright
После установки необходимо инициализировать браузеры (скачать бинарные файлы Chromium, Firefox и WebKit):
python -m playwright install
Теперь можно написать код для запуска браузера. Пример кода для открытия страницы выглядит следующим образом:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True) # Запуск браузера Chromium
page = browser.new_page() # Создание новой страницы
page.goto("https://example.com") # Переход на сайт
print(page.title()) # Вывод заголовка страницы
browser.close() # Закрытие браузера
В данном примере используется синхронный API Playwright. Браузер запускается, открывается новая страница, осуществляется переход на указанный URL, и выводится заголовок страницы.
Пояснения:
headless=True— браузер работает без графического интерфейса (по умолчанию). Удобно для серверов или CI/CD.headless=False— можно визуально наблюдать за действиями браузера. Полезно при отладке.page.goto(url)— открывает страницу. Можно указать таймаут:page.goto(url, timeout=10000).
Работа с селекторами — как найти элементы на странице
После загрузки страницы нужно найти конкретные элементы: кнопку для клика, поле для ввода текста, заголовок для проверки. Для этого используются селекторы — способы описать, какой именно элемент нас интересует.
Селекторы позволяют находить элементы на веб-странице. Playwright поддерживает несколько типов селекторов:
CSS-селекторы:
page.locator("button.submit")
Найдет все кнопки с классом submit.
XPath:
page.locator("//button[@id='submit']")
Позволяет точнее находить элементы, особенно в сложной структуре HTML. В этом примере:
//— область поиска по всему документу. Не важно, где находится элемент: в<body>, внутри<div>или глубоко вложен, в отличие от/, который задаёт жёсткий путь от корня.button— тип узла. Ищем HTML-элемент<button>. Другие элементы (input,a,div) не подойдут.[@id='submit']— фильтр. Квадратные скобки — условие отбора.@id— обращение к атрибутуid.'submit'— точное значение.- В итоге: выбрать со всей страницы только те
<button>, у которыхid="submit".
Текстовые селекторы:
page.locator("text=Отправить")
Ищет элемент по тексту.
Лучше использовать locator, а не старый query_selector, потому что локатор поддерживает встроенные ожидания и автоматически ждёт появления и готовности элементов для взаимодействия.
Ожидания — работа с динамическим контентом
Современные сайты часто загружают контент динамически: кнопка появляется после загрузки JavaScript, данные подгружаются через API. Если попытаться кликнуть на элемент, которого ещё нет на странице, получим ошибку. Для этого нужны ожидания.
Ожидания необходимы для корректного взаимодействия с элементами, которые могут загружаться асинхронно. В Playwright есть два основных способа ожиданий:
-
Встроенные ожидания локаторов
Методы локатора (click(),fill(),inner_text()и другие) автоматически дожидаются, пока элемент:- появится в DOM (Document Object Model),
- станет видимым,
- станет доступным для взаимодействия.
Пример:
heading = page.locator("h1") # ждёт, пока h1 станет доступен print(heading.inner_text()) heading.click(timeout=3000) # тоже ждёт готовности элементаЗдесь нет необходимости явно вызывать
wait_for_selector()— Playwright всё делает сам. -
Ожидание навигации
Иногда требуется дождаться перехода на другую страницу после действия пользователя (например, после клика по ссылке):page.locator("a#next").click() # Клик по ссылке page.wait_for_navigation() # Явное ожидание завершения перехода
Отличие от старого подхода
При использовании query_selector методы не ждут элемент, поэтому часто нужно делать:
page.wait_for_selector("h1", timeout=5000) # ждёт до 5 секунд
element = page.query_selector("h1")
print(element.inner_text())
Локаторы делают это автоматически, упрощая код и снижая вероятность ошибок из-за асинхронной загрузки контента.
Параметр wait_until — когда страница считается загруженной
Когда мы вызываем page.goto(), возникает вопрос: когда считать, что страница загружена? Когда HTML получен? Когда все картинки скачаны? Когда JavaScript выполнился?
wait_until определяет, когда Playwright считает, что переход на страницу завершён.
page.goto("https://example.com", wait_until="load")
Варианты:
load— происходит, когда всё: DOM + ресурсы (картинки, CSS, JS) загружено. Это классическое поведение по умолчанию.commit— срабатывает сразу после того, как браузер получил ответ на основной запрос и начал загрузку документа. Не ждёт CSS, JS или изображений. Полезно, если нужно моментально начать работу с DOM, не дожидаясь полной загрузки.domcontentloaded— срабатывает, когда HTML-документ полностью загружен и распарсен, но ресурсы (картинки, стили, шрифты) могут ещё загружаться. Полезно для SPA, где JS сам подгружает данные, или скриптов, которые работают с DOM сразу после загрузки.networkidle(устаревший) — считается завершённым, когда нет сетевых соединений ≥ 500 мс. Раньше использовался для SPA, чтобы ждать подгрузки API-запросов. Сейчас Playwright не рекомендует использовать, так как это часто непредсказуемо — иногда сетевые пулы остаются открытыми. Рекомендуется ждать конкретный элемент на странице через селектор или ответ от сети черезwait_for_response, чтобы точно определить готовность нужного контента.
Ретраи (Retries) — устойчивость к временным сбоям
Даже стабильные сайты иногда тормозят или недоступны из-за сетевых проблем. Вместо того чтобы падать с ошибкой, лучше повторить попытку.
Иногда сайты временно недоступны, и лучше повторить действие, чем падать:
from playwright.sync_api import TimeoutError
for attempt in range(3):
try:
page.goto("https://news.ycombinator.com/")
break # если успешно — выход из цикла
except TimeoutError:
print(f"Попытка {attempt + 1} не удалась. Повтор...")
else:
print("Не удалось загрузить страницу после 3 попыток")
- Повторные попытки позволяют обрабатывать временные сбои сети или замедленную загрузку страниц.
- Комбинируется с ожиданиями для устойчивой работы.
Ошибки и крайние случаи
При работе с Playwright могут возникать различные ошибки:
- Элемент не найден: Если указанный селектор не соответствует ни одному элементу на странице, будет выброшено исключение.
- Таймаут ожидания: Если элемент не появился в течение заданного времени, будет выброшено исключение о таймауте.
- Проблемы с навигацией: Если переход на новую страницу не завершился, это может привести к ошибкам.
Даже на стабильных сайтах могут быть неожиданные изменения (редизайн, обновление структуры), поэтому блоки try/except обязательны:
try:
page.locator("button.submit").click()
except Exception as e:
print("Не удалось нажать кнопку:", e)
Рекомендации:
- Логируйте ошибки с помощью
printилиlogging. - Используйте скриншоты при ошибках для понимания, что пошло не так:
page.screenshot(path="error.png")
Работа с несколькими страницами и вкладками
Иногда нужно работать с несколькими сайтами одновременно или открыть ссылку в новой вкладке. Playwright позволяет открывать несколько вкладок и работать с ними независимо:
page1 = browser.new_page()
page1.goto("https://example.com")
page2 = browser.new_page()
page2.goto("https://example.org")
- Каждая вкладка — отдельный контекст для действий.
- Можно параллельно взаимодействовать с несколькими страницами.
Асинхронное API
Для высокой производительности (например, одновременная обработка десятков страниц) Playwright полностью поддерживает async/await. Пример:
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto("https://example.com")
# Клик по ссылке
await page.locator("text=Learn more").click()
# Получаем весь текст страницы
page_text = await page.inner_text("body")
print(page_text)
await browser.close()
asyncio.run(main())
Артефакты: скриншоты и видео
Для диагностики проблем (особенно в CI/CD, где нет возможности визуально наблюдать) полезно сохранять визуальные артефакты:
1. Скриншоты:
page.screenshot(path="screenshot.png")
2. Запись видео сессии:
context = browser.new_context(record_video_dir="videos/")
page = context.new_page()
page.goto("https://example.com/")
# По окончании:
context.close() # видео сохраняется в папку videos/
Итоги
Playwright позволяет полностью управлять браузером, поддерживает синхронное и асинхронное взаимодействие с элементами. С помощью селекторов и ожиданий можно надежно находить и взаимодействовать с элементами страницы, даже если они загружаются динамически. Встроенные механизмы ожиданий, ретраи и возможность записи артефактов делают автоматизацию браузера стабильной и удобной для отладки.
Дальше по курсу
Разберём как изолировать процессы, а также работать с контекстом выполнения (куки, локальное хранилище).
