今天是综合实战!!涉及到请求,逆向,解密,爬取。
目标是从某音乐软件的评论区爬取热评,可以说是大开眼界了!
#1.找到未加密的参数 #window.asrsea(参数1,参数2,参数3.。。。。。) #2.想办法把参数进行加密,(使用的是某云的加密逻辑) #params->encText encSecKey->enSecKey #3.请求到网页,拿到评论信息
1.打开网页,输入你想要的了解的歌
2.进入子网页,抓包,一个个检查看评论的包在哪里,这里显示的是已经抓到评论区的包,可以看到评论区的url需要两个参数params,encSecKey.这两个参数就是涉及到加密的参数,我们就是要需要破解整个加密的逻辑
3.点击启动器,显示的是各个json文件,最上面的是最后处理的文件,我们开始从后往前倒推。点击第一个json文件
4.在定位点设置断点,刷新网页。
5.刷新之后,在作用域里面关注本地这个选项,打开变量查看requests属性,然后点击上方蓝色按钮,不断放开直到出现我们想要的评论的url.
6.在调用堆栈里面,一个一个json文件查看我们所需要的参数:encText,encSecKey,直到找到这个参数值,这个就是我们的加密参数。我们可以看到它们是属于
var bVj8b这个变量的,而这个变量又是由 window.asrsea这个函数赋值的,所以我们猜想,由window.asrsea这个函数进行加密,我们搜索这个函数
7.除了在调用的时候出现了这个函数,前面还定义了这个函数,这个函数又是由d函数赋值来的,我们解读一下d这个函数,这里我把a,b,c,d,e五个函数都抄下来了,我们一个一个解读。说实话这里的f,e,g是固定值这个怎么看出来的我忘记了,只记得d是data数据,i是随机数,从而确定了encSecKey.而相对应的encText就是我们要的params。如果想深入了解可以看这个视频
2021年最新Python爬虫教程+实战项目案例(最新录制)_哔哩哔哩_bilibili
!function() {
function a(a) {#由i值来的
var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
for (d = 0; a > d; d += 1)
e = Math.random() * b.length,#产生e的随机数
e = Math.floor(e),#对e向下取整
c += b.charAt(e);#e作为b的索引,从b中拿出一个索引为e的字符,附到c上
return c#返回c,这就是a函数的功能,产生一个随机秘钥
}
function b(a, b) {#b函数时加密过程,为AES加密,a是加密内容,b是加密秘钥
var c = CryptoJS.enc.Utf8.parse(b)
, d = CryptoJS.enc.Utf8.parse("0102030405060708")
, e = CryptoJS.enc.Utf8.parse(a)#把a的utf-8格式赋值给e
, f = CryptoJS.AES.encrypt(e, c, {#AES加密,把e和c加密
iv: d,#iv为AES加密的偏移量
mode: CryptoJS.mode.CBC#AES的加密模式
});
return f.toString()#返回f的字符串形式
}
function c(a, b, c) {
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b,"",c),
e = encryptedString(d, a)
}
function d(d, e, f, g) {#由window.asrsea来的
var h = {}#创建空字典
, i = a(16);#i值由a函数确定,i值为16位的随机秘钥
return h.encText = b(d, g),#b函数的返回值写进h的encText内,d是待加密数据
h.encText = b(h.encText, i),#可以看出这是两次加密过程,生成encText
h.encSecKey = c(i, e, f),
#encSecKey这个参数就是我们想要的两个参数之一,由c函数确定
#这里c函数需要传进去的参数有i e f ,其中e f 是定值,i是随机值,我们把i值固定就能获得固定的encSecKey值
#至此encSecKey和encText的加密过程全部确定完毕。
h
}
function e(a, b, d, e) {
var f = {};
return f.encText = c(a + e, b, d),
f
}
window.asrsea = d,
window.ecnonasr = e
}();
剩下的就是所有的代码,后续如果还有时间会重新回来梳理这个逻辑,这个帖子写的我自己都不是很满意。
#1.找到未加密的参数 #window.asrsea(参数1,参数2,参数3.。。。。。)
#2.想办法把参数进行加密,(使用的是网易云的加密逻辑) #params->encText encSecKey->enSecKey
#3.请求到网页,拿到评论信息
import requests
from Crypto.Cipher import AES
from base64 import b64encode
import json #json 可以把字典变成字符串
url="https://music.163.com/weapi/comment/resource/comments/get?csrf_token="
#请求方式post
data={
"csrf_token": "",
"cursor": "-1",
"offset": "0",
"orderType": "1",
"pageNo": "1",
"pageSize": "20",
"rid": "R_SO_4_40257799",
"threadId": "R_SO_4_40257799"
}
#处理加密过程
""""
function a(a) {#返回随机的16位字符串
var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
for (d = 0; a > d; d += 1)#循环函数
e = Math.random() * b.length,#生成随机数
e = Math.floor(e),#取整
c += b.charAt(e);#取字符串中的xxx位
return c
}
function b(a, b) {#a是要加密的内容,b是秘钥
var c = CryptoJS.enc.Utf8.parse(b)#c是utf-8的b
, d = CryptoJS.enc.Utf8.parse("0102030405060708")#d是数字的utf-8类型
, e = CryptoJS.enc.Utf8.parse(a)#e是a的utf-8形式
, f = CryptoJS.AES.encrypt(e, c, {#AES加密算法,
iv: d,#AES算法里面的偏移量
mode: CryptoJS.mode.CBC#模式:CBC,差一个秘钥,秘钥就是c,c又是b,所以b的作用就是秘钥
});
return f.toString()
}
function c(a, b, c) {#c算法不产生随机数
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b,"",c),
e = encryptedString(d, a)
}
function d(d, e, f, g) {d:d就是数据,e:01001,f:'很长',g:'0CoJUm6Qyw8W8jud'}
var h = {}#声明空对象
, i = a(16);#i是16位的随机字符串
return h.encText = b(d, g),#所以d是数据,g是秘钥
h.encText = b(h.encText, i),#这里得到的encText就是我们要的params,i是秘钥
#从上面两行代码看出,想要得到encText,首先需要两次b加密过程,第一次数据+g,第二次把第一次返回的结果+i
h.encSecKey = c(i, e, f),#这里得到的encSeckey就是我们要的encSeckey,e,f都是固定值,i是随机值
#这里encSeckey的随机值产生都是由于i的原因,我们把i值固定就能获得固定的encSeckey值.
h
}
function e(a, b, d, e) {
var f = {};
return f.encText = c(a + e, b, d),
f
}
"""
f="00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
i="5wWcgz0OQm8BE9yI"#随机值
e="010001"
g="0CoJUm6Qyw8W8jud"
def get_encSeckey():#由i确定
return "c5c0039e144f4dad02c2fc54dd0a6dcf74c0981748c1c00acba22d79569963ce4434a0f9663a1a048bcc4afbf4d4a389477323ef79b13673439ebb5d1d9895f6ea06c0fcc612e8e475dafca50bed9f51a3a07407be7739f86bd790ff10936947a6f022ec38db5c069968c559f17a617f8546a37dc3b900a469f9c19e0f85873a"
# 把参数进行加密
def get_params(data): # 默认这里接收到的是字符串
first = enc_params(data, g)
second = enc_params(first, i)
return second # 返回的就是params
# 转化成16的倍数, 为下方的加密算法服务
def to_16(data):
pad = 16 - len(data) % 16
data += chr(pad) * pad
return data
# 加密过程
def enc_params(data, key):
iv = "0102030405060708"
data = to_16(data)
aes = AES.new(key=key.encode("utf-8"), IV=iv.encode('utf-8'), mode=AES.MODE_CBC) # 创建加密器
bs = aes.encrypt(data.encode("utf-8")) # 加密, 加密的内容的长度必须是16的倍数
return str(b64encode(bs), "utf-8") # 转化成字符串返回,
resp=requests.post(url,data={
"params":get_params(json.dumps(data)),
"encSecKey":get_encSeckey()#Key写成了key,结果一直出不来!!!!!!!!!!!!!!!
})
print(resp.text)
最后的效果如图