Playwright 的 page.on("websocket") 仅捕获连接建立/关闭事件,无法获取帧数据;需通过 CDP 的 Network.webSocketFrameReceived 事件监听,且仅 Chromium 支持,须提前启用并手动解码 base64 载荷。

Playwright 本身不支持直接监听 WebSocket 消息
Playwright 的 page.on("websocket") 仅能捕获 WebSocket 连接的建立与关闭事件,无法获取实际收发的帧数据。这是官方明确限制的行为——它把 WebSocket 当作黑盒网络连接处理,不暴露底层消息流。如果你看到文档里有 WebSocket 类,那只是个空壳,没有 onmessage 或 frames() 这类方法。
真正能拿到推送数据的方式,只有两条路:一是改用 Puppeteer(Node.js),二是绕过 Playwright 的封装,用浏览器 DevTools Protocol(CDP)手动注入监听逻辑。
用 CDP 启用 WebSocket 消息捕获(Chrome/Edge)
Playwright 支持通过 page.context.new_cdp_session(page) 获取 CDP 会话,再启用 Network.enable 并监听 Network.webSocketFrameReceived 事件。注意:该能力仅在 Chromium 内核浏览器(Chrome、Edge)中可用,Firefox 和 WebKit 不支持。
- 必须在页面加载前启用 CDP 监听,否则会漏掉初始连接帧
-
Network.webSocketFrameReceived的response.payloadData是 base64 编码的原始字节,需用base64.b64decode()解码后按 UTF-8 或二进制解析 - WebSocket URL 需提前知道或从
Network.webSocketCreated事件中提取,不能靠正则模糊匹配所有 ws:// 地址(CDP 不提供通配过滤)
from playwright.sync_api import sync_playwright
import base64
<p>with sync_playwright() as p:
browser = p.chromium.launch()
context = browser.new_context()
page = context.new_page()</p><pre class="brush:php;toolbar:false;"># 必须在 navigate 前创建 CDP 会话
cdp = context.new_cdp_session(page)
cdp.send("Network.enable")
ws_messages = []
def on_ws_frame(event):
if event.get("response", {}).get("opcode") == 1: # text frame
payload = event["response"]["payloadData"]
try:
decoded = base64.b64decode(payload).decode("utf-8")
ws_messages.append(decoded)
except UnicodeDecodeError:
pass # binary frame,按需处理
cdp.on("Network.webSocketFrameReceived", on_ws_frame)
page.goto("https://example-ws-app.com")
# 后续操作触发 WS 推送...
立即学习“Python免费学习笔记(深入)”;
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
为什么不用 page.route() 拦截 WebSocket 请求?
page.route() 对 ws:// 和 wss:// 协议完全无效——Playwright 的路由拦截只作用于 HTTP/HTTPS 流量,WebSocket 握手请求(GET)虽走 HTTP,但升级后的长连接通道不在路由控制范围内。试图对 ws://* 写 route 规则会静默失败,没有任何报错或回调触发。
常见误操作是想用 page.route("wss://*", ...) 拦截握手响应头,这也不可行:Playwright 不允许修改 WebSocket 握手的响应(如 Sec-WebSocket-Accept),且即使能改,也无法接管后续帧传输。
真实场景下的取舍建议
如果你要做的只是验证某条关键推送是否到达(比如“订单已支付”通知),优先考虑在页面 JS 中埋点:WebSocket.prototype.send = new_send 和重写 onmessage,再用 page.evaluate() 注入并监听全局变量;比 CDP 更稳定、兼容性更好。
如果必须做全量抓包分析(例如调试协议字段、压测吞吐),就只能接受 CDP 方案的局限:仅限 Chromium、需手动解码、无法过滤特定连接、且容易因页面跳转或 iframe 导致监听丢失。这时候别指望 Playwright 提供“开箱即用”的 WebSocket 调试能力——它真没这个设计目标。

















