如何使用 puppeteer 转储 WebSocket 数据

How to use puppeteer to dump WebSocket data

我想获取这个页面的websocket数据https://upbit.com/exchange?code=CRIX.UPBIT.KRW-BTC,它的websocketURL是动态的,只在第一次连接时有效,第二次连接就不会再发送数据了.

所以我想知道也许 headless chrome 可以帮助我监控 websocket 数据。

有什么想法吗?谢谢!

我认为 puppeteer 尚不支持此功能,但较低级别的协议 支持 此处:https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-webSocketFrameSent and https://chromedevtools.github.io/devtools-protocol/tot/Network#type-WebSocketResponse。这意味着如果您愿意,也可以自己在库中实现它。

您实际上不需要为此做任何复杂的事情。 URL 虽然看起来是动态的,但通过代码也能正常工作。它不起作用的原因是您需要了解后台发生的事情。

首先让我们看看“网络”选项卡。

cookie 和 Origin 可能对连接很重要。所以我们把这些记下来。

现在让我们看看套接字上的数据交换

如果您查看初始帧接收 o 作为数据的帧,这可能表示正在打开连接。然后网站向socket发送一些数据,这可能与我们要查询的内容有关。当连接暂停一段时间后,套接字接收 h 作为数据。这可能表示暂停或其他内容(如第二张图片所示)

为了获得准确的数据,我们在代码中放置了一个断点

然后在控制台打印值

现在我们有足够的信息可以进入编码部分了。我发现下面是一个很好的 websocket 库

https://github.com/websockets/ws

所以我们做一个

yarn add ws || npm install ws --save

现在我们写代码

const WebSocket = require("ws")
const ws = new WebSocket("wss://example.com/sockjs/299/enavklnl/websocket",null,{
    headers: {
        "Cookie":"<cookie data noted earlier>",
        "User-Agent": "<Your browser agent>"
    },
    origin: "https://example.com",
})
const opening_message = '["[{\"ticket\":\"ram macbook\"},{\"type\":\"recentCrix\",\"codes\":[\"CRIX.UPBIT.KRW-BTC\",\"CRIX.BITFINEX.USD-BTC\",\"CRIX.BITFLYER.JPY-BTC\",\"CRIX.OKCOIN.CNY-BTC\",\"CRIX.KRAKEN.EUR-BTC\",\"CRIX.UPBIT.KRW-DASH\",\"CRIX.UPBIT.KRW-ETH\",\"CRIX.UPBIT.KRW-NEO\",\"CRIX.UPBIT.KRW-BCC\",\"CRIX.UPBIT.KRW-MTL\",\"CRIX.UPBIT.KRW-LTC\",\"CRIX.UPBIT.KRW-STRAT\",\"CRIX.UPBIT.KRW-XRP\",\"CRIX.UPBIT.KRW-ETC\",\"CRIX.UPBIT.KRW-OMG\",\"CRIX.UPBIT.KRW-SNT\",\"CRIX.UPBIT.KRW-WAVES\",\"CRIX.UPBIT.KRW-PIVX\",\"CRIX.UPBIT.KRW-XEM\",\"CRIX.UPBIT.KRW-ZEC\",\"CRIX.UPBIT.KRW-XMR\",\"CRIX.UPBIT.KRW-QTUM\",\"CRIX.UPBIT.KRW-LSK\",\"CRIX.UPBIT.KRW-STEEM\",\"CRIX.UPBIT.KRW-XLM\",\"CRIX.UPBIT.KRW-ARDR\",\"CRIX.UPBIT.KRW-KMD\",\"CRIX.UPBIT.KRW-ARK\",\"CRIX.UPBIT.KRW-STORJ\",\"CRIX.UPBIT.KRW-GRS\",\"CRIX.UPBIT.KRW-VTC\",\"CRIX.UPBIT.KRW-REP\",\"CRIX.UPBIT.KRW-EMC2\",\"CRIX.UPBIT.KRW-ADA\",\"CRIX.UPBIT.KRW-SBD\",\"CRIX.UPBIT.KRW-TIX\",\"CRIX.UPBIT.KRW-POWR\",\"CRIX.UPBIT.KRW-MER\",\"CRIX.UPBIT.KRW-BTG\",\"CRIX.COINMARKETCAP.KRW-USDT\"]},{\"type\":\"crixTrade\",\"codes\":[\"CRIX.UPBIT.KRW-BTC\"]},{\"type\":\"crixOrderbook\",\"codes\":[\"CRIX.UPBIT.KRW-BTC\"]}]"]'
ws.on('open', function open() {
    console.log("opened");
});

ws.on('message', function incoming(data) {
    if (data == "o" || data == "h") {
        console.log("sending opening message")
        ws.send(opening_message)
    }
    else {
        console.log("Received", data)

    }
});

和运行我们得到的代码

现在如果我替换

const ws = new WebSocket("wss://example.com/sockjs/299/enavklnl/websocket",null,{
    headers: {
        "Cookie":"<cookie data noted earlier>",
        "User-Agent": "<Your browser agent>"
    },
    origin: "https://example.com",
})

const ws = new WebSocket("wss://example.com/sockjs/299/enavklnl/websocket")

这意味着从来不需要 cookiesorigin。但我仍然建议您使用它们

const client = page._client

client.on('Network.webSocketCreated', ({requestId, url}) => {
  console.log('Network.webSocketCreated', requestId, url)
})

client.on('Network.webSocketClosed', ({requestId, timestamp}) => {
  console.log('Network.webSocketClosed', requestId, timestamp)
})

client.on('Network.webSocketFrameSent', ({requestId, timestamp, response}) => {
  console.log('Network.webSocketFrameSent', requestId, timestamp, response.payloadData)
})

client.on('Network.webSocketFrameReceived', ({requestId, timestamp, response}) => {
  console.log('Network.webSocketFrameReceived', requestId, timestamp, response.payloadData)
})

直接使用 DevTools 协议 - https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webSocketClosed