Skip to main content

网络 (Network)

Playwright 提供 API 来 监控修改 网络流量,包括 HTTP 和 HTTPS。页面发出的任何请求,包括 XHRfetch 请求,都可以被跟踪、修改和处理。

HTTP Authentication

使用 browser.new_context(**kwargs) 执行 HTTP 认证。

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

HTTP Proxy

您可以配置页面通过 HTTP(S) 代理或 SOCKSv5 加载。代理可以为整个浏览器全局设置,也可以为每个浏览器上下文单独设置。

您可以选择为 HTTP(S) 代理指定用户名和密码,也可以指定绕过代理的主机。

这是一个全局代理的示例:

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

当单独为每个上下文指定代理时,Windows 上的 Chromium 需要提示将设置代理。这是通过向浏览器本身传递一个非空代理服务器来完成的。这是一个特定于上下文的代理示例:

# Browser proxy option is required for Chromium on Windows.
browser = chromium.launch(proxy={"server": "per-context"})
context = browser.new_context(proxy={"server": "http://myproxy.com:3128"})

Network events

您可以监控所有 RequestResponse

from playwright.sync_api import sync_playwright

def run(playwright):
chromium = playwright.chromium
browser = chromium.launch()
page = browser.new_page()
# Subscribe to "request" and "response" events.
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_or_predicate, **kwargs) 等待网络响应:

# Use a glob url pattern
with page.expect_response("**/api/fetch_data") as response_info:
page.get_by_text("Update").click()
response = response_info.value

Variations

使用 page.expect_response(url_or_predicate, **kwargs) 等待 Response

# Use a regular expression
with page.expect_response(re.compile(r"\.jpeg$")) as response_info:
page.get_by_text("Update").click()
response = response_info.value

# Use a predicate taking a response object
with page.expect_response(lambda response: token in response.url) as response_info:
page.get_by_text("Update").click()
response = response_info.value

Handle requests

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

您可以通过在 Playwright 脚本中处理网络请求来模拟 API 端点。

Variations

使用 browser_context.route(url, handler, **kwargs) 在整个浏览器上下文或使用 page.route(url, handler, **kwargs) 在页面上设置路由。它将应用于弹出窗口和打开的链接。

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

Modify requests

# Delete header
def handle_route(route):
headers = route.request.headers
del headers["x-secret"]
route.continue_(headers=headers)
page.route("**/*", handle_route)

# Continue requests as POST.
page.route("**/*", lambda route: route.continue_(method="POST"))

您可以继续带有修改的请求。上面的示例从传出请求中删除了 HTTP 头。

Abort requests

您可以使用 page.route(url, handler, **kwargs)route.abort(**kwargs) 中止请求。

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

# Abort based on the request type
page.route("**/*", lambda route: route.abort() if route.request.resource_type == "image" else route.continue_())

Modify responses

要修改响应,请使用 APIRequestContext 获取原始响应,然后将响应传递给 route.fulfill(**kwargs)。您可以通过选项覆盖响应上的各个字段:

def handle_route(route: Route) -> None:
# Fetch original response.
response = page.request.fetch(route.request)
# Add a prefix to the title.
body = response.text()
body = body.replace("<title>", "<title>My prefix:")
route.fulfill(
# Pass all fields from the response.
response=response,
# Override response body.
body=body,
# Force content type to be html.
headers={**response.headers, "content-type": "text/html"},
)

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

Record and replay requests

您可以将网络活动录制为 HTTP 归档文件 (HAR)。稍后,此归档可用于模拟对网络请求的响应。您需要:

  1. 录制 HAR 文件。
  2. 将 HAR 文件与测试一起提交。
  3. 在测试中使用保存的 HAR 文件路由请求。

Recording HAR with CLI

使用 Playwright CLI 打开浏览器并传递 --save-har 选项以生成 HAR 文件。或者,使用 --save-har-glob 仅保存您感兴趣的请求,例如 API 端点。如果 har 文件名以 .zip 结尾,则工件将作为单独的文件写入,并全部压缩为单个 zip

# Save API requests from example.com as "example.har" archive.
playwright open --save-har=example.har --save-har-glob="**/api/**" https://example.coms

Recording HAR with a script

或者,您可以以编程方式录制 HAR,而不是使用 CLI。使用 browser.new_context(**kwargs) 创建 BrowserContext 时传递 har 选项以创建归档。如果 har 文件名以 .zip 结尾,则工件将作为单独的文件写入,并全部压缩为单个 zip

context = browser.new_context(record_har_path="example.har", record_har_url_filter="**/api/**")

# ... Perform actions ...

# Close context to ensure HAR is saved to disk.
context.close()

Replaying from HAR

使用 page.route_from_har(har, **kwargs)browser_context.route_from_har(har, **kwargs)HAR 文件提供匹配的响应。

# Either use a matching response from the HAR,
# or abort the request if nothing matches.
page.route_from_har("example.har")

HAR 回放严格匹配 URL 和 HTTP 方法。对于 POST 请求,它还严格匹配 POST 负载。如果多个录制匹配一个请求,则选择具有最多匹配头的录制。导致重定向的条目将被自动跟随。

与录制时类似,如果给定的 HAR 文件名以 .zip 结尾,则将其视为包含 HAR 文件以及存储为单独条目的网络负载的归档。您还可以提取此归档,手动编辑负载或 HAR 日志,并指向提取的 har 文件。所有负载都将相对于文件系统上提取的 har 文件进行解析。

WebSockets

Playwright 开箱即用地支持 WebSockets 检查。每次创建 WebSocket 时,都会触发 page.on("websocket") 事件。此事件包含用于进一步检查 Web Socket 帧的 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)

Missing Network Events and Service Workers

Playwright 内置的 browser_context.route(url, handler, **kwargs)page.route(url, handler, **kwargs) 允许您的测试原生路由请求并执行模拟和拦截。

  1. 如果您正在使用 Playwright 的原生 browser_context.route(url, handler, **kwargs)page.route(url, handler, **kwargs),并且似乎缺少网络事件,请通过将 browser.new_context.service_workers 设置为 'block' 来禁用 Service Workers。
  2. 可能是您正在使用模拟工具,例如 Mock Service Worker (MSW)。虽然此工具开箱即用地用于模拟响应,但它添加了自己的 Service Worker 来接管网络请求,从而使它们对 browser_context.route(url, handler, **kwargs)page.route(url, handler, **kwargs) 不可见。如果您对网络测试和模拟都感兴趣,请考虑使用内置的 browser_context.route(url, handler, **kwargs)page.route(url, handler, **kwargs) 进行 响应模拟
  3. 如果您不仅对使用 Service Workers 进行测试和网络模拟感兴趣,而且对路由和监听 Service Workers 本身发出的请求感兴趣,请参阅 此实验性功能