因为宿舍想搞个云顶之弈排名,我并没有找到腾讯官方查询战绩的网站,所以决定对云顶官网的排行榜下手,云顶官网的数据排行网页(下链接)对排名的显示是一个可以滑动的divbox
https://lol.qq.com/tft/#/rank/list
可以发现当鼠标放到排行榜上滑动滚轮时,后续排名数据会被不断显示出来,推断这个排名数据应该是被js动态加载出来的,不能通过简单爬html文件的方式抓取到,所以必须通过找到ajax请求的方式用python模拟发送请求进而获得服务器返回数据。
在浏览器开发者模式中打开<网络>选项卡,在排行榜上滑动滚轮时,每滑动几下就会出现一些网络请求,进行筛选后,得到形如
“http://qt.qq.com/lua/mlol_battle_info/get_total_tier_rank_list?area_id=XX&offset=XX&sign=XX”
的post请求url,用request.post()进行测试后,发现其返回值是一个json对象(如下图所示)
,内包含20个人的ID,排名,段位等信息,其中area_id是所在大区id,offset为排名(如想得到20-40名的数据offset就为20,网页每划过20人就对服务器发送一次请求),sign是网页为了反爬虫而设下的签名值,每次请求都不一样,要爬取所有的数据,就要对sign的生成进行解析,才能每次发送正确的请求得到数据。因为ajax请求一定是由js发送的,所以在网页的js文件中找到请求发送函数就能看到sign签名的生成过程,寻找后发现在"api.js"中可以找到如下代码段
getAreaTierRank: function (area_id, offset) {
// 获取sign参数
var params = "area_id=" + area_id + "&offset=" + offset;
var key = "qtld^xibt#a*";
var sign = hex_md5(params + key);
// body数据
var withdata = {
next_offset: "",
player_list: []
};
return this.baseRequestPromise('//qt.qq.com/lua/mlol_battle_info/get_total_tier_rank_list?area_id=' + area_id + '&offset=' + offset + '&sign=' + sign, {
credentials: 'include',
method: 'POST',
body: JSON.stringify(withdata)
});
}
sign是由hex_md5()函数计算出来的,其中传参params是一段当前url内的字符串,key值则为一个规定好的字符串,md5是一个加密算法,只要得到传入的字符串,我们就可以也用md5算法得到sign值,至此请求url被解析完成,后续就是用python自动生成每次请求的url,得到所有返回值并进行格式处理就可以了。下面粘上源代码
import requests
import hashlib
def signCal(areaID,offset):
str1 = 'area_id='+areaID+'&offset='+str(offset)+'qtld^xibt#a*' #用于计算sign签名的字符串,最后一项为key
b = str1.encode(encoding='utf-8')
m = hashlib.md5()
m.update(b)
str_md5 = m.hexdigest() #MD5编码
return str_md5
def getReqURL(areaID,count):
offset = 20*count;
str_ = "http://qt.qq.com/lua/mlol_battle_info/get_total_tier_rank_list?" #请求url前面不变部分
return str_+'area_id='+areaID+'&offset='+str(offset)+'&sign='+signCal(areaID,offset) #请求url
name = []
ranking = []
points = []
title = [] #存储返回数据
for i in range(0,1): #一次请求有20个数据,range()中可以随意填写[0,250]内数,以获取前5000名数据
r= requests.post(getReqURL('12',i)) #得到返回数据
tem = r.json()
temm = tem['data']['player_list']
for a in temm:
name.append(a['name'])
ranking.append(a['ranking'])
points.append(a['league_points'])
title.append(a['tier_title']) #解析
k = 0
for j in name:
print(str(k+1)+'\tname: '+str(name[k])+'\ttitle: '+str(title[k])+'\tranking: '+str(ranking[k])+'\tpoints: '+str(points[k]))
k+=1
输出(无畏先锋服务器4981-5000名为例):