# 前戏
之前的博客由于太久没有维护,又懒得翻新了,所以索性重新搭建了一个,看着主页空荡荡的,所以随便写一篇 js 逆向爬虫,这次的 “受害者” 是红人点集。
废话不多说,教程开始。
网址: 网址
# 正片
# 逻辑分析
打开控制台,刷新网页,在网络记录里选择 XHR 类(别问,问就是 Ajax),可以看到一个 api 如下 (图片有点糊,将就一下吧)
点开 api 的表单数据,可以看到
对这几个参数,param 和 tenant 不用说肯定是定值,对于 sign,timestamp,token 则有可能是加密变化参数,(不要忘了,对于 token,有可能是定值,例如登录账号后会生成一个此账号的固定 token),对页面进行多次刷新,比对可以发现 token 确实是不变的,仅是 sign 和 timestamp 变化。
则搜索源代码 sign,即可找到 sign 在代码中的位置,如下(搜索找位置此处省略)
可以看到四个参数都在,并且参数值为变量,则可以判断是此处无疑
在 sign 处打上断点(timestamp 打也是一样的),刷新网页,此时页面停在断点处(再次证明此处代码是要找的)
将鼠标停在加密 sign 的 E 函数上,则可跳转到 E 函数(省略图片),如下
发现 E 函数是返回了一个值,这个值是通过 k 函数进行加密的,于是用同上方法跳转到 k 函数,如下
# 逻辑梳理
看到整个加密逻辑了过后,来进行一遍梳理,并运用 python 模拟加密逻辑
其中 timestamp 为时间戳,即
time_get=str(int(time.time())*1000) |
对于 sign, 我们先分析 k 函数,k 函数是对传入的参数进行 sha256 加密,即
def sha256(self,value): | |
sha=hashlib.sha256() | |
sha.update(value.encode('utf-8')) | |
return sha.hexdigest() |
而 E 函数则是将 param,timestamp,tenant,salt 进行拼接并返回其进行 sha256 加密的值(对于 salt 的值,即 C,可以将鼠标放在上面查看)
注:此处拼接结果为
time_get=str(int(time.time())*1000) | |
params={"no":"dy0002","data":{"days":1,"rankType":7}} | |
dd=json.dumps(params) | |
text = f'param={dd}×tamp={time_get}&tenant=1&salt=kbn%&)@<?FGkfs8sdf4Vg1*+;`kf5ndl$' |
其中 text 则为拼接结果
# 结果
最后请求 api 的时候带上 headers 和表单数据,即可返回 json 类型的数据,对数据进行处理即可,效果图如下:
# 完整代码
代码中的 token 值请各位自行登录获取
import requests | |
import hashlib | |
import time | |
import json | |
class Spider: | |
def __init__(self): | |
self.api='https://ucp.hrdjyun.com:60359/api/dy' | |
self.headers={ | |
"Accept": "application/json, text/plain, */*", | |
"Accept-Encoding": "gzip, deflate, br", | |
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", | |
"Connection": "keep-alive", | |
"Content-Length": "248", | |
"Content-Type": "application/json;charset=UTF-8", | |
"Host": "ucp.hrdjyun.com:60359", | |
"Origin": "http://www.hh1024.com", | |
"sec-ch-ua": "\"Not_A Brand\";v=\"99\", \"Microsoft Edge\";v=\"109\", \"Chromium\";v=\"109\"", | |
"sec-ch-ua-mobile": "?0", | |
"sec-ch-ua-platform": "\"Windows\"", | |
"Sec-Fetch-Dest": "empty", | |
"Sec-Fetch-Mode": "cors", | |
"Sec-Fetch-Site": "cross-site", | |
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.52" | |
} | |
def sha256(self,value): | |
sha=hashlib.sha256() | |
sha.update(value.encode('utf-8')) | |
return sha.hexdigest() | |
def spider(self): | |
time_get=str(int(time.time())*1000) | |
params={"no":"dy0002","data":{"days":1,"rankType":7}} | |
dd=json.dumps(params) | |
text = f'param={dd}×tamp={time_get}&tenant=1&salt=kbn%&)@<?FGkfs8sdf4Vg1*+;`kf5ndl$' | |
sign =self.sha256(text) | |
data={ | |
"param":dd, | |
"sign":sign, | |
"tenant":"1", | |
"timestamp":time_get, | |
"token":"你的token" | |
} | |
session=requests.session() | |
session.headers=self.headers | |
response=session.post(self.api,data=json.dumps(data)) | |
print(response.json()) | |
if response.json().get('status') == 0: | |
data = response.json().get('data')['rankList'] | |
for d in data: | |
items = {} | |
items['抖音名'] = d.get('anchorName') | |
items['销量'] = d.get('displaySales') | |
items['销售额'] =d.get('displayMoney') | |
items['粉丝'] ='%.2f'% (d.get('fans')/10000) +'万' | |
items['热度'] =d.get('gmv_score') | |
print(items) | |
if __name__=='__main__': | |
Spider().spider() |