Перейти к основному содержимому

Сеть

Введение​

Playwright предоставляет API для мониторинга и модификации сетевого трафика браузера, как HTTP, так и HTTPS. Любые запросы, которые делает страница, включая XHR и fetch запросы, могут быть отслежены, изменены и обработаны.

Мокирование API​

Ознакомьтесь с нашим руководством по мокированию API, чтобы узнать больше о том, как

  • мокировать API-запросы и никогда не обращаться к API
  • выполнять API-запрос и изменять ответ
  • использовать HAR-файлы для мокирования сетевых запросов.

HTTP-аутентификация​

Выполнение HTTP-аутентификации.

context = browser.new_context(
http_credentials={"username": "bill", "password": "pa55w0rd"}
)
page = context.new_page()
page.goto("https://example.com")

HTTP-прокси​

Вы можете настроить страницы для загрузки через HTTP(S) прокси или SOCKSv5. Прокси может быть установлен глобально для всего браузера или для каждого контекста браузера отдельно.

Вы можете дополнительно указать имя пользователя и пароль для HTTP(S) прокси, а также указать хосты, которые нужно обойти прокси.

Вот пример глобального прокси:

browser = chromium.launch(proxy={
"server": "http://myproxy.com:3128",
"username": "usr",
"password": "pwd"
})

Также возможно указать его для каждого контекста:

browser = chromium.launch()
context = browser.new_context(proxy={"server": "http://myproxy.com:3128"})

Сетевые события​

Вы можете отслеживать все Request и Response:

from playwright.sync_api import sync_playwright, Playwright

def run(playwright: Playwright):
chromium = playwright.chromium
browser = chromium.launch()
page = browser.new_page()
# Подписка на события "request" и "response".
page.on("request", lambda request: print(">>", request.method, request.url))
page.on("response", lambda response: print("<<", response.status, response.url))
page.goto("https://example.com")
browser.close()

with sync_playwright() as playwright:
run(playwright)

Или дождаться сетевого ответа после нажатия кнопки с помощью page.expect_response():

# Используйте шаблон URL с глобальными символами
with page.expect_response("**/api/fetch_data") as response_info:
page.get_by_text("Update").click()
response = response_info.value

Вариации​

Ожидание Response с page.expect_response()

# Используйте регулярное выражение
with page.expect_response(re.compile(r"\.jpeg$")) as response_info:
page.get_by_text("Update").click()
response = response_info.value

# Используйте предикат, принимающий объект ответа
with page.expect_response(lambda response: token in response.url) as response_info:
page.get_by_text("Update").click()
response = response_info.value

Обработка запросов​

page.route(
"**/api/fetch_data",
lambda route: route.fulfill(status=200, body=test_data))
page.goto("https://example.com")

Вы можете мокировать конечные точки API, обрабатывая сетевые запросы в вашем скрипте Playwright.

Вариации​

Настройте маршрут для всего контекста браузера с помощью browser_context.route() или страницы с помощью page.route(). Это будет применяться к всплывающим окнам и открытым ссылкам.

context.route(
"**/api/login",
lambda route: route.fulfill(status=200, body="accept"))
page.goto("https://example.com")

Изменение запросов​

# Удаление заголовка
def handle_route(route):
headers = route.request.headers
del headers["x-secret"]
route.continue_(headers=headers)
page.route("**/*", handle_route)

# Продолжение запросов как POST.
page.route("**/*", lambda route: route.continue_(method="POST"))

Вы можете продолжать запросы с модификациями. Пример выше удаляет HTTP-заголовок из исходящих запросов.

Прерывание запросов​

Вы можете прерывать запросы, используя page.route() и route.abort().

page.route("**/*.{png,jpg,jpeg}", lambda route: route.abort())

# Прерывание на основе типа запроса
page.route("**/*", lambda route: route.abort() if route.request.resource_type == "image" else route.continue_())

Изменение ответов​

Чтобы изменить ответ, используйте APIRequestContext для получения оригинального ответа, а затем передайте ответ в route.fulfill(). Вы можете переопределить отдельные поля в ответе с помощью опций:

def handle_route(route: Route) -> None:
# Получить оригинальный ответ.
response = route.fetch()
# Добавить префикс к заголовку.
body = response.text()
body = body.replace("<title>", "<title>My prefix:")
route.fulfill(
# Передать все поля из ответа.
response=response,
# Переопределить тело ответа.
body=body,
# Принудительно установить тип контента как html.
headers={**response.headers, "content-type": "text/html"},
)

page.route("**/title.html", handle_route)

Шаблоны URL с глобами​

Playwright использует упрощённые glob-шаблоны для сопоставления URL в методах перехвата сети, таких как page.route() или page.expect_response(). Эти шаблоны поддерживают базовые подстановочные символы:

  1. Звёздочки:
    • Одна * сопоставляет любые символы, кроме /
    • Две ** сопоставляют любые символы, включая /
  2. Знак вопроса ? сопоставляет только сам символ ?. Если нужно сопоставить любой символ, используйте *.
  3. Фигурные скобки {} можно использовать, чтобы сопоставлять список вариантов, разделённых запятыми ,
  4. Обратный слэш \ можно использовать для экранирования любых специальных символов (учтите, что сам обратный слэш нужно экранировать как \\)

Примеры:

  • https://example.com/*.js сопоставляет https://example.com/file.js, но не https://example.com/path/file.js
  • https://example.com/?page=1 сопоставляет https://example.com/?page=1, но не https://example.com
  • **/*.js сопоставляет и https://example.com/file.js, и https://example.com/path/file.js
  • **/*.{png,jpg,jpeg} сопоставляет все запросы изображений

Важные заметки:

  • Шаблон с глобами должен соответствовать всему URL, а не только его части.
  • При использовании глобов для сопоставления URL учитывайте полную структуру URL, включая протокол и разделители пути.
  • Для более сложных требований к сопоставлению рассмотрите возможность использования [RegExp] вместо шаблонов с глобами.

WebSockets​

Playwright поддерживает инспекцию, имитацию и модификацию WebSockets из коробки. Ознакомьтесь с нашим руководством по имитации API, чтобы узнать, как имитировать WebSockets.

Каждый раз, когда создается WebSocket, срабатывает событие page.on("websocket"). Это событие содержит экземпляр WebSocket для дальнейшей инспекции фреймов веб-сокета:

def on_web_socket(ws):
print(f"WebSocket opened: {ws.url}")
ws.on("framesent", lambda payload: print(payload))
ws.on("framereceived", lambda payload: print(payload))
ws.on("close", lambda payload: print("WebSocket closed"))

page.on("websocket", on_web_socket)

Отсутствующие сетевые события и Service Workers​

Встроенные методы Playwright — browser_context.route() и page.route() — позволяют тестам нативно маршрутизировать запросы, а также выполнять мокирование и перехват.

Если вы используете нативные browser_context.route() и page.route(), и вам кажется, что сетевые события пропадают, отключите Service Worker’ы, установив service_workers в 'block'.

Возможно, вы используете инструмент для моков, например Mock Service Worker (MSW). Хотя он отлично работает для мокирования ответов, он добавляет собственный Service Worker, который перехватывает сетевые запросы — из‑за этого они становятся невидимыми для browser_context.route() и page.route(). Если вам нужно и тестировать сеть, и делать моки, рассмотрите использование встроенных browser_context.route() и page.route() для мокирования ответов.