【2020-10-29】记一次WebSocket握手验证反爬虫


前言

查了下最新的反爬虫方式,看到一个WebSocket握手验证反爬虫,还没有遇到过,找了个网站试一试~
最新反爬方式:https://blog.csdn.net/qq_26079939/article/details/109356139


一、WebSocket是什么?

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

二、WebSocket握手验证反爬虫

1.目标网站

乐鱼体育:https://live.611.com/zq


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 的响应头

猜你喜欢

转载自blog.csdn.net/qq_26079939/article/details/109361489