Skip to main content

网络 (Network)

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

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​

您可以监控所有 Request 和 Response:

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 本身发出的请求感兴趣,请参阅 此实验性功能。