前言
查了下最新的反爬虫方式,看到一个WebSocket握手验证反爬虫,还没有遇到过,找了个网站试一试~
最新反爬方式:https://blog.csdn.net/qq_26079939/article/details/109356139
一、WebSocket是什么?
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
二、WebSocket握手验证反爬虫
1.目标网站
2.网站分析
1.建立Socket链接的地址,其中9394adf88ece4ff08f9ac6e82949f3a1
参数是变值
2.通过如下方式获取token
def getToken():
url = "https://live.611.com/Live/GetToken"
response = requests.get(url)
if response.status_code == 200:
data = json.loads(response.text)
token = data["Data"]
return token
else:
print("请求错误")
3.从下面的图可以看出,绿色的箭头是客户端发送给服务器的数据,红色箭头是服务器响应的数据
3.获取数据
Python 库中用于连接 WebSocket 的有很多,但是易用、稳定的有 websocket-client(非异步)、websockets(异步)、aiowebsocket(异步),以下用websocket-client和websockets方式实现。
websocket-client方法:
import requests
import websocket
import json
import time
def getToken(): # 获取token参数
url = "https://live.611.com/Live/GetToken"
response = requests.get(url)
if response.status_code == 200:
data = json.loads(response.text)
token = data["Data"]
return token
else:
print("请求错误")
def get_message(): # 需要发送的数据
timestamp = int(time.time()) * 1000
info = {
'chrome': 'true', 'version': '80.0.3987.122', 'webkit': 'true'}
message1 = {
"command": "RegisterInfo",
"action": "Web",
"ids": [],
"UserInfo": {
"Version": str([timestamp]) + json.dumps(info),
"Url": "https://live.611.com/zq"
}
}
message2 = {
"command": "JoinGroup",
"action": "SoccerLiveOdd",
"ids": []
}
message3 = {
"command": "JoinGroup",
"action": "SoccerLive",
"ids": []
}
return json.dumps(message1), json.dumps(message2), json.dumps(message3)
def Download(token,message1,message2,message3):
uri = "wss://push.611.com:6119/{}".format(token)
ws = websocket.create_connection(uri, timeout=10)
ws.send(message1)
ws.send(message2)
ws.send(message3)
while True:
result = ws.recv()
print(result)
if __name__ == '__main__':
token = getToken() # 获取token字符串
message1, message2, message3 = get_message() # 构造请求信息
Download(token,message1, message2,message3) # 抓取数据
运行结果
websockets方法
import asyncio
import logging
import time,json,requests
from aiowebsocket.converses import AioWebSocket
def getToken():
url = "https://live.611.com/Live/GetToken"
response = requests.get(url)
if response.status_code == 200:
data = json.loads(response.text)
token = data["Data"]
return token
else:
print("请求错误")
def get_message(): # 需要发送的数据
timestamp = int(time.time()) * 1000
info = {
'chrome': 'true', 'version': '80.0.3987.122', 'webkit': 'true'}
message1 = {
"command": "RegisterInfo",
"action": "Web",
"ids": [],
"UserInfo": {
"Version": str([timestamp]) + json.dumps(info),
"Url": "https://live.611.com/zq"
}
}
message2 = {
"command": "JoinGroup",
"action": "SoccerLiveOdd",
"ids": []
}
message3 = {
"command": "JoinGroup",
"action": "SoccerLive",
"ids": []
}
return message1, message2, message3
async def startup():
token = getToken() # 获取token字符串
uri = "wss://push.611.com:6119/{}".format(token)
message1, message2,message3 = get_message() # 构造请求信息
async with AioWebSocket(uri) as aws:
converse = aws.manipulator
await converse.send(json.dumps(message1))
await converse.send(json.dumps(message2))
await converse.send(json.dumps(message3))
while True:
mes = await converse.receive()
if mes:
msg = json.loads(str(mes, encoding="utf-8"))
print(msg)
if __name__ == '__main__':
try:
asyncio.get_event_loop().run_until_complete(startup())
except KeyboardInterrupt as exc:
logging.info('Quit.')
运行结果
总结
Web 领域中,用于实现数据’实时’更新的手段有轮询和 WebSocket 这两种。轮询指的是客户端按照一定时间间隔(如 1 秒)访问服务端接口,从而达到 ‘实时’ 的效果,虽然看起来数据像是实时更新的,但实际上它有一定的时间间隔,并不是真正的实时更新。轮询通常采用 拉 模式,由客户端主动从服务端拉取数据。
WebSocket 采用的是 推 模式,由服务端主动将数据推送给客户端,这种方式是真正的实时更新。
服务器端创建 socket 服务后监听客户端,使用 while True 的方式读取客户端发送的消息
然后对服务器端发送的握手请求进验证,如果验证通过,则返回状态码为 101 的响应头,否则返回状态码为 403 的响应头