|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 大马强 于 2021-9-1 15:36 编辑
爬取网易云的评论,关键是获得两个加密参数 params, enSeckey
一、事前准备
以这首歌THE ANSWER为例,打开Chrome浏览器的调试工具, 点击newwork,重新刷新一下看看浏览器请求回来的数据包,找有评论信息的数据包,点击Initiator js脚本调用栈,点击最上方的也是最后一次执行的js脚本
二、找到未加密的数据
进入之后发现当前的内容是“不堪入目”的,先点击左下角的 “{}” ,让其阅读性好一点,然后将当前位置设置一个断点,浏览器不单单只请求评论的数据包,所以我们要观察旁边的Scope栏中变量,一步一步放掉不需要的请求,直到当浏览器请求https://music.163.com/weapi/comm ... nts/get?csrf_token=
然后再通过js栈中调用的js来寻找到未加密前的数据第一次出现的js,那么它的下一次js就是将参数加密,之后再重新设置一个断点,一步步调试找到该js加密参数的具体地方
目标锁定 window.asrsea函数, ctrl + F 寻找该函数具体实现的地方,找到了d函数,加密的过程就是再d函数里实现的了
三、找到加密原理
观察d函数可以发现,d函数有四个参数,与window.asrsea 函数的四个参数一一对应,利用浏览器的调试工具就可以得到参数的值。d函数中调用了两次b函数,一次a函数和一次c函数,再进一步观察其他函数,发现a函数作用时返回一个16为随机数给i变量,b函数是加密的params参数,c函数是加密的encSecKey参数
b,c函数分别用到了AES加密和RSA加密,前者AES加密的第一次加密是将d作为明文,g作为密钥,第二次加密是将第一次加密的密文再进行加密,i作为第二次加密的密钥,最终的带加密的params。后者用到三个参数 i,e,f,三个值都是定值,所以参数encSecKey可以固定下来
- function a(a) {a =16
- var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
- for (d = 0; a > d; d += 1) 循环16次,创建一个16位随机字符串
- e = Math.random() * b.length,
- e = Math.floor(e),
- c += b.charAt(e);
- return c
- }
- function b(a, b) { a = 数据, g:定值, 经过AES加密 原文,密钥,偏移量,模式
- var c = CryptoJS.enc.Utf8.parse(b) b
- , d = CryptoJS.enc.Utf8.parse("0102030405060708")
- , e = CryptoJS.enc.Utf8.parse(a)
- , f = CryptoJS.AES.encrypt(e, c, { e 原文, c :密钥
- iv: d, 偏移量
- mode: CryptoJS.mode.CBC 模式
- });
- return f.toString()
- }
- function c(a, b, c) {
- var d, e;
- return setMaxDigits(131),
- d = new RSAKeyPair(b,"",c), <-密钥
- e = encryptedString(d, a) <-公钥加密 d:公钥 ,a
- }
- function d(d, e, f, g) { d: 数据data, e:"010001", f:一个很长的字符串, g:"0CoJUm6Qyw8W8jud"
- var h = {}
- , i = a(16); -生成随机数
- return h.encText = b(d, g),d=数据, g密钥
- h.encText = b(h.encText, i), param :
- encText两层加密
- -- 可以将i定死,encSecKey就是一个定值
- h.encSecKey = c(i, e, f), i :16位随机值,e定值,f定值 encSecKey
- h
- }
复制代码
四、实现代码
- from Crypto.Cipher import AES
- from base64 import b64encode
- import requests
- import json
- import random
- url = "https://music.163.com/weapi/comment/resource/comments/get?csrf_token="
- data = {
- "cursor": "-1",
- "offset": "0",
- "orderType": "1",
- "pageNo": "1",
- "pageSize": "20",
- "rid": "R_SO_4_1855995767",
- "threadId": "R_SO_4_1855995767"
- }
- # 函数d四个参数
- def get_i():
- seq = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
- str1 = ""
- for i in range(16):
- str1 += random.choice(seq)
- print(str1)
- return str1
- e = "010001"
- d = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
- g = "0CoJUm6Qyw8W8jud"
- i = "p6xB1rx37AU8O0KO"
- def get_encSeckey():
- return "b742226290709f51abf9ad9a4e9136bd89036078368545a3f9a5ab938068d7a7be4d3f3fc2ea184090def069b85f75e4b443a43b1a872710c22ce983a3785fc074e799bd90d3e22a7a14d8a4864d647a72dc3a0de05a10ac61ef8114b631bf0079708ff79e0c2901ce0db1c26be78503550f65be6490ad08125ebf9744cc41cf"
- # 补位
- def to_16(data):
- pd = 16 - len(data) % 16
- data += chr(pd) * pd
- return data
- def get_param(data): # 字典1是加密不了的,需要处理成字符串
- # param 是经过两次加密的
- first = enc_param(data, g)
- second = enc_param(first, i)
- return second
- def enc_param(data, key):
- iv = "0102030405060708"
- # 创建一个AES加密器, 设置密钥,偏移量以及模式,前两者要为字符串格式
- # AEs加密的数据格式一定是16的倍数,不到就用chr(x)补齐 格式为 "123456788chr(7)chr(7)"
- data = to_16(data)
- aes = AES.new(key=key.encode("utf-8"),
- iv=iv.encode("utf-8"), mode=AES.MODE_CBC)
- # 加密后返回结果为字节,但需要的是字符串,并且该返回不能被 utf-8 格式所识别,还需要借助其他的库将其转换
- bs = aes.encrypt(data.encode("utf-8"))
- return str(b64encode(bs), "utf-8")
- # 将字典转换成字符串 ,需要json
- req = requests.post(url, data={
- "params": get_param(json.dumps(data)),
- "encSecKey": get_encSeckey()
- })
- res = req.json()["data"]["hotComments"]
- for content in res:
- print(content["content"])
复制代码
|
|