WebSocket 通信原理【底层】:原来你是这样的Websocket–抓包分析
Python 爬取 WebSocket【顶层】:Python如何爬取实时变化的WebSocket数据的方法
注意:可以直接参考上述链接,解释地很详细。
1. WebSocket 介绍
2. 分析
3. 编写爬序
4. 其它
5. 总结
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。【摘自 - 百度百科】
补充【自己的理解】:客户端发起ws/wss协议链接请求(类似于http/https协议的链接请求),当中会有一次握手(状态码为101则为成功建立)。每次建立后首先由客户端发起消息到服务器,服务器验证返回信息(互相发送信息可能不止一次,才到服务器真正的返回有用的数据。)如下图所示:
上图中,绿色箭头向上是客户端(如浏览器)发送信息给服务器,红色箭头向下是服务器发送信息给客户端。可以看出前面几次信息发送相当于验证过程。
根据参考链接中给出的例子,是一个很好地例子。这里也用这个例子尝试一下。
网站链接:莱特币中国官方网站Litecoin
选择WS选项卡,找到realTime
从图中,我们找到的信息有:realTime是websocket类型,状态码为101(建立成功)
找到socket链接,可以编写程序【具体原理分析可以看参考链接的第二个】
socket:wss://api.bbxapp.vip/v1/ifcontract/realTime
代码 copy 来的,这些 Python代码 不太熟:
import asyncio #异步
import logging # 日志
from datetime import datetime #时间
from aiowebsocket.converses import AioWebSocket #aiowebsocket需要安装,异步websocket
async def startup(uri): # anync 异步语法
async with AioWebSocket(uri) as aws:
converse = aws.manipulator
# 客户端给服务端发送消息
await converse.send('{"action":"subscribe","args":["QuoteBin5m:14"]}') # await 也是异步语法
while True:
mes = await converse.receive()
print('{time}-Client receive: {rec}'
.format(time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'), rec=mes))
if __name__ == '__main__':
remote = 'wss://api.bbxapp.vip/v1/ifcontract/realTime'
try:
asyncio.get_event_loop().run_until_complete(startup(remote))
except KeyboardInterrupt as exc:
logging.info('Quit.')
解释:
当中最重要的是一句是:
await converse.send('{"action":"subscribe","args":["QuoteBin5m:14"]}')
这相当于下图验证的过程:
对应查看,直到客户端发送此条信息,服务器才源源不断地发送信息:
最终运行效果图:
红色的就是websocket,可以看到状态码为101,建立成功
细节查看(与浏览器基本一致,可能有人说浏览器也可以做到,要Fiddler有什么用,这就可以体现出作为强大抓包软件的性能,Fiddler可以轻松地抓到手机包,要是手机app用websocket通信不就可以抓取了):
添加Fiddler日志,查看详细细节:
(1) 在菜单栏中,打开Rules - Customize Rules
(2)添加一下代码到上述窗口中的 class Handlers里
static function OnWebSocketMessage(oMsg: WebSocketMessage) {
// Log Message to the LOG tab
FiddlerApplication.Log.LogString(oMsg.ToString());
}
(3)添加结果,保存
(4)效果【出现关于websocket更详细地日志】
相关链接:使用jmeter对websocket进行压力测试
还记得有时候需要发送一些数据验证,服务器才会不断发送数据。之前遇到一个问题,就是客户端上传2probe给服务器,所以思考一个问题,2probe是什么?为什么要2probe?难受啊 我天?
后来查找资料的时候发现,就把它当成一段数据(字符串)发送给服务器就可以。
如:
await converse.send('2probe')
注意:客户端可能不是仅仅发送一条2probe数据,服务器就开始返还所需数据,可能还需要继续发送,所要做就是模拟客户端发送/接受的过程即可:
如:
await converse.send('2probe')
mes = await converse.receive()
await converse.send('2')
mes = await converse.receive()
.
.
.
mes = await converse.receive() # 直到收到正确的数据
python UnicodeEncodeError: 'UCS-2' codec can't encode characters in position 1-1: Non-BMP character
怎么办?解决方案:‘UCS-2’ codec can’t encode characters in position 1050-1050
import sys
non_bmp_map = dict.fromkeys(range(0x10000, sys.maxunicode + 1), 0xfffd)
print(x.translate(non_bmp_map))
注意:x是字符串,替换为想要解决问题的地方
主要写了Python爬取WebSocket的初尝试,因为对WebSocket还不是很了解,而且异步编程还没有学会,虽然语法很简单,但是怎么看怎么变扭。我觉得很多东西,都是上手简单,理解难,看的多了自然就通了。如同当初刚开始接触Python的类编写的时候,真的非常痛苦,完全无法理解为什么要这么写,或者说为什么我写的不通过,他写地就通过了。难受啊。虽然无法理解,但是我一直看、写,总算是理解一部分。后来,读了《Learning Python 5th Edition》这本书后,我终于可以理解类为什么这么写。实例和类本身的关系【继承树概念的形成很重要】。好吧,扯远了。
好吧,让我们一起加油吧!ヾ(◍°∇°◍)ノ゙
Fin.