WebSocket消息不经过HTTP栈,开发者工具Network面板仅显示Upgrade握手请求;需通过JS劫持WebSocket原型、mitmproxy代理或Playwright的websocket事件捕获。

WebSocket数据不在HTTP流量里,抓包工具默认看不到
浏览器开发者工具的Network面板只显示HTTP/HTTPS请求,WebSocket连接建立后的真实消息(send() / onmessage)不会出现在那里。你看到的只是初始的HTTP Upgrade握手请求,后续二进制或文本帧完全绕过HTTP栈。
真正要拦截数据,得从运行时入手——要么注入JS劫持WebSocket构造函数和原型方法,要么用代理工具(如mitmproxy)配合自定义WebSocket处理逻辑。直接用requests或urllib无法捕获已建立连接中的消息流。
用JavaScript重写WebSocket.prototype实现前端数据捕获
这是最常用、见效最快的方案,适合你已能控制目标页面(比如自己写的页面,或通过浏览器扩展注入脚本)。核心是保存原始构造函数,再覆盖send()和onmessage行为:
const originalWS = window.WebSocket;
window.WebSocket = function(url, protocols) {
const ws = new originalWS(url, protocols);
const originalSend = ws.send;
ws.send = function(data) {
console.log('[WS SEND]', data); // 或发到自己的监听端
return originalSend.call(this, data);
};
const originalOnMessage = ws.onmessage;
ws.onmessage = function(event) {
console.log('[WS RECEIVE]', event.data);
if (originalOnMessage) originalOnMessage.call(this, event);
};
return ws;
};- 必须在页面加载
WebSocket实例创建前执行该脚本,否则已有实例不受影响 -
event.data可能是String、ArrayBuffer或Blob,需用typeof或instanceof判断后再处理 - 若页面使用
addEventListener('message')而非onmessage,还需劫持addEventListener并过滤message事件
用mitmproxy + websocket-client做中间代理捕获
适用于不能修改前端代码的场景(比如分析第三方网站),但要求你能让目标浏览器走你的代理,并且目标WebSocket服务支持ws://(wss://因TLS终止问题较难透明代理)。
立即学习“Python免费学习笔记(深入)”;
mitmproxy本身不解析WebSocket帧,需搭配websocket-client手动建立隧道并转发:
from mitmproxy import http
from websocket import create_connection
<p>def request(flow: http.HTTPFlow) -> None:
if flow.request.pretty_url == "ws://example.com/ws":</p><h1>启动一个真实WS连接,把flow当管道用</h1><pre class='brush:python;toolbar:false;'> ws = create_connection("ws://example.com/ws")
# 此处需另起线程双向转发消息,实际代码比这复杂得多注意:mitmproxy v10+ 已移除对WebSocket的原生支持,上述方式仅适用于简单测试;生产级拦截更推荐用BrowserMob Proxy(Java)或直接改用Playwright/Puppeteer的page.on('websocket')事件(Chromium系支持)。
Playwright中监听WebSocket消息最稳定
如果你的目标是自动化分析,Playwright(v1.40+)提供了开箱即用的page.on('websocket')事件,能拿到连接对象及其on('framesent')和on('framereceived')钩子:
from playwright.sync_api import sync_playwright
<p>with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.on("websocket", lambda ws: (
ws.on("framesent", lambda f: print("SENT:", f)),
ws.on("framereceived", lambda f: print("RECV:", f))
))
page.goto("<a href="https://www.php.cn/link/b05edd78c294dcf6d960190bf5bde635">https://www.php.cn/link/b05edd78c294dcf6d960190bf5bde635</a>")- 仅限Chromium和Firefox(Webkit暂不支持),且必须启用
--enable-features=NetworkService -
f是WebSocketFrame对象,f.payload为str或bytes,无需手动解帧 - 不能拦截加密的
wss://帧内容(TLS层已加密),但能看到明文传输的字段值
真实环境中,WebSocket常伴随token刷新、心跳保活、分片帧等细节,单纯看单条onmessage容易漏掉关键上下文。建议始终结合console.log输出时间戳和连接ID,再按会话聚合分析。


















