闲来无事,找个简单的网站练练手,于是盯上了某体育网站,嗯。。。重点是简单~
目标:足球板块实时赛事数据
工具:chrome/firefox浏览器、pycharm、python3.7
模块:requests、time、websocket
1、打开chrome浏览器开始分析https://live.611.com/zq,发现网页html结构中数据都是动态加载的,我也没有点刷新,接着发现响应主体中并没有数据,那么数据应该是通过js动态加载,而要做到数据实时更新(以我目前的知识储备)那要么就是ajax请求,要么是websocket实时推送,应该还有其他方法可以实现,这里就拿这两个接着分析;
2、接着浏览器筛选XHR、WS,果然其中就有一个websocket,打开Messages,发现浏览器向服务器发送了三次信息,接着就是服务器一直推送数据过来,点开其中一个推送的数据,发现这个网站确实是通过WebSocket实时更新数据的;
3、接着分析浏览器向服务器发送了什么内容,初略一看都是json格式数据,那么只要搞清楚里面是什么参数,哪些是固定、哪些是变动的,固定的不变,只要修改变动的参数就行了。
参数分析:
{“command”:“RegisterInfo”,“action”:“Web”,“ids”:[],“UserInfo”:{“Version”:"[1604733914000]{“chrome”:true,“version”:“86.0.4240.183”,“webkit”:true}",“Url”:“https://live.611.com/zq”}}
{“command”:“JoinGroup”,“action”:“SoccerLiveOdd”,“ids”:[]}
{“command”:“JoinGroup”,“action”:“SoccerLive”,“ids”:[]}
通过多次刷新页面/更换浏览器得出结论:
第一条内容是连接服务器用的,action、ids、Url都是不变的,只有UserInfo里面内容是变化的,其中Version中括号里面是一个时间戳+000,后面加浏览器参数,那么只需要更改时间戳就可以了,浏览器参数直接复制就行。
第二、三条内容是加入群组用的,参数都是固定的,不需要改。
4、分析完发送的内容,后面就容易了,只需要再得到url就可以尝试连接了,返回headers界面,发现url后面加了一段字符串参数,字符串每次刷新后都不同,应该是js加密生成的,找js文件逆向太麻烦,先看看前面的请求有没有这个参数;
结果发现这个参数是请求https://www.611.com/Live/GetToken这个接口得到的,其中的data就是这个加密参数,那么只需要在连接websocket前,请求这个接口得到这个参数,再加到wss://push.611.com:6119/后面就行。
到此分析结束,开始写代码:
1、首先定义一个函数获取token
import requests
def get_token():
# 获取token
url = 'https://www.611.com/Live/GetToken'
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36'
}
return requests.get(token_url, headers=header, verify=False).json()['Data']
2、接着定义一个类,初始化url、websocket,具体代码如下:
import time
import websocket
class Leyu:
def __init__(self):
# 获取token
self.token = get_token()
# 初始化服务器地址
self.wss_url = 'wss://push.611.com:6119/{}'.format(self.token)
# 初始化websocket
self.socket = websocket.WebSocketApp(self.wss_url, on_message=self.on_message,
on_error=self.on_error, on_close=self.on_close, on_open=self.on_open)
def login(self):
# 向服务器发送连接信息
msg = '{"command":"RegisterInfo","action":"Web","ids":[],"UserInfo":{"Version":"[' + str(int(time.time())) + '000' + ']{\\"chrome\\":true,\\"version\\":\\"86.0.4240.183\\",\\"webkit\\":true}","Url":"https://live.611.com/zq"}}'
self.socket.send(msg)
def join_group(self):
# 向服务器发送入组信息
msg1 = '{"command":"JoinGroup","action":"SoccerLiveOdd","ids":[]}'
msg2 = '{"command":"JoinGroup","action":"SoccerLive","ids":[]}'
self.socket.send(msg1)
self.socket.send(msg2)
def on_message(self, message):
# 输出服务器推送过来的内容
print(message)
def on_error(self, error):
# 报错
print('报错:', error)
def on_close(self):
# 关闭连接
pass
def on_open(self):
# 连接服务器
self.login()
print('连接成功!')
self.join_group()
def run(self):
# 运行循环
self.socket.run_forever()
if __name__ == '__main__':
ly = Leyu()
ly.run()
由于服务器传的数据太多,就没有一个个解析了,解析过程太繁琐,这些数据对我没啥用。这次主要目的是成功连接获取到服务器推过来的数据就行。另外,连接websocket还有一个异步库可以用,aiowebsocket,发现还挺方便的,通过公众号FightingCoder例子初步了解,直接贴代码:
import asyncio
import requests
import logging
import time
from aiowebsocket.converses import AioWebSocket
def get_token():
url = 'https://www.611.com/Live/GetToken'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36'
}
return requests.get(url, headers=headers, verify=False).json()['Data']
async def startup(uri):
async with AioWebSocket(uri) as aws:
converse = aws.manipulator
# 向服务器发送消息
await converse.send('{"command":"RegisterInfo","action":"Web","ids":[],"UserInfo":{"Version":"[' + str(int(time.time())) + '000' + ']{\\"chrome\\":true,\\"version\\":\\"86.0.4240.183\\",\\"webkit\\":true}","Url":"https://live.611.com/zq"}}')
await converse.send('{"command":"JoinGroup","action":"SoccerLiveOdd","ids":[]}')
await converse.send('{"command":"JoinGroup","action":"SoccerLive","ids":[]}')
while True:
mes = await converse.receive()
print(mes)
if __name__ == '__main__':
token = get_token()
remote = 'wss://push.611.com:6119/{}'.format(token)
try:
asyncio.get_event_loop().run_until_complete(startup(remote))
except KeyboardInterrupt as exc:
logging.info('Quit.')
遇到的问题:在这过程中写完代码运行后发现服务器只推送了一条信息过来就立即自动断开了,死活没找到原因,结果检查代码后发现是发给服务器的第一条信息中反斜杠的问题,浏览器在发信息给服务器的时候参数中有反斜杠,直接复制过来的内容只有一个反斜杠,而python中反斜杠是转义用的,所以需要再加一个反斜杠对反斜杠进行转义,最后成功连接没有自动断开。
总结:整个过程其实就是分析,分析数据获取方式,分析链接,分析参数,代码写起来就比较容易了。这个网站貌似没什么反爬措施,作为一个练手的项目还是不错的。