1、需求
2、工具
pip install pycryptodomex #用Cryptodome.Cipher里的AES加密
3、url和参数以及加密过程查找
点栈元素,跳到sources,在光标处设置断点重新刷新。
所以要找的参数实际上是:params=>encText,encSecKey=>encSecKey
需要找到加密的处理函数。
剩余三个参数可以看是什么值。
找到处理加密过程,即找window.asrsea(参数,…)
固定i的值。
4、处理加密过程爬取评论及解析
# comprehensive case
# 爬取网易云评论
import json
import requests
import base64
from Cryptodome.Cipher import AES
import jsonpath
import re
# 需求:
# 1.找到未加密的参数 #通过window.asrsea(参数,...)进行加密
# 2.按照原来的加密方式把参数进行加密,实际上:params=>encText,encSecKey=>encSecKey
# 3.请求url拿到数据
url = "https://music.163.com/weapi/comment/resource/comments/get?csrf_token="
#真实的参数
data = { #字典
"csrf_token": "",
"cursor":"-1",
"offset": "0",
"orderType": "1",
"pageNo": "1",
"pageSize": "20",
"rid": "R_SO_4_29004400",
"threadId": "R_SO_4_29004400"
}
# 处理加密过程,即找window.asrsea(参数,...)源头
# d = JSON.stringify(i0x) #实参也就是data
e = "010001"
f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
g = "0CoJUm6Qyw8W8jud"
#在加密过程中i为随机值,在i取值后设置断点得到i的值,将i固定值不变
i = "hJmVIJGZI4uNku8O"
def to16(data):
#转化为16位的长度
add = 16 - len(data) % 16
data = str(data)
# for i in range(0,add):
# data += " "
data += chr(add) * add # 要添add个字节,chr()表示字节
return data
def get_encSecKey():
# i固定之后得到的encSecKey
encSecKey = "a399da91613e7804adffa10983935885caf040325eea0f8f83daf9544ecdc640ac87d366e3c5ce80a726c808e3d43d811cb56aadddc49d2e20ef9f138d8565ca59dc5d98eea82b90f935c003de9a3b112c9aed05c267d6d177d6eb6d43ea224e6bdd54030fb72399184a0f44cc36d41f322d8e200063873f11c7f76b6df7020f"
return encSecKey
#对数据进行加密
def get_params(data): #data为字符串
#还原d中的encText,调用了b
first = get_encText(data,g)
second = get_encText(first,i)
return second
def get_encText(data,key): #data为字符串
# 还原b中的转换和AES加密过程
iv = "0102030405060708"
#创建加密对象
aes = AES.new(key=key.encode("utf-8"),mode=AES.MODE_CBC,IV=iv.encode("utf-8"))
# 补足16的倍数
data = to16(data)
#完成加密
dataAes = aes.encrypt(data.encode("utf-8")) #加密内容的长度必须是16的倍数,不能只为16
#用b64encode编码
dataAes = base64.b64encode(dataAes)
#密钥转化为字符串
dataAes = str(dataAes,"utf-8")
return dataAes
"""
!function() {
function a(a) { # a = 16
var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
for (d = 0; a > d; d += 1)
e = Math.random() * b.length, #取0-b.length的随机数
e = Math.floor(e), #向下取整
c += b.charAt(e); #检索字符串b中特定位置e的字符累加到c
return c #返回16长度的字符串
}
function b(a, b) { # a为要加密的内容
var c = CryptoJS.enc.Utf8.parse(b) # b也为密钥
, d = CryptoJS.enc.Utf8.parse("0102030405060708") #字符串为IV
, e = CryptoJS.enc.Utf8.parse(a) # e 为数据
, f = CryptoJS.AES.encrypt(e, c, { #AES为加密方法,c为机密的密钥
iv: d, #偏移量
mode: CryptoJS.mode.CBC #CBC的加密模式
});
return f.toString()
}
function c(a, b, c) { #不产生随机数
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b,"",c),
e = encryptedString(d, a)
}
在scope中
d = JSON.stringify(i0x) #实参也就是data
e = "010001"
f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
g = "0CoJUm6Qyw8W8jud"
主要找d的取值
function d(d, e, f, g) {
var h = {}
, i = a(16); #i是长度为16的随机字符串,根据以下可以把i设为定值
# encText进行两次加密
h.encText = b(d, g), #返回字符串(utf-8),g为最开始的密钥,为定值
h.encText = b(h.encText, i), #实际encText=>params,i也是密钥,为定值
h.encSecKey = c(i, e, f), #实际为encSecKey=>encSecKey,参数除了i都为定值。因为c中无随机数,所以方法:固定i的值,得到encSecKey为固定值
return h
}
function e(a, b, d, e) {
var f = {};
return f.encText = c(a + e, b, d),
f
}
window.asrsea = d,
window.ecnonasr = e
}();
"""
def craw():
resp = requests.post(url, data={
"params": get_params(json.dumps(data)), # json.dumps(data) 把字典转为字符串
"encSecKey": get_encSecKey()
})
page_content = json.loads(resp.text) # 以json格式保存到文件
resp.close()
return page_content
def writeAsJson(page_content):
with open(r"attachment/comments.json",mode="w",encoding="utf-8") as f:
json.dump(page_content,f,ensure_ascii=False,indent=2)
f.close()
return
jsonData = ""
with open("attachment/comments.json",'r',encoding='utf-8') as f:
jsonData = json.load(f) #json文件以原格式读出
f.close()
#解析
nicknameList = []
contentList = []
timeStrList = []
# print(type(jsonData)) #dic
nicknameList = jsonpath.jsonpath(jsonData,'$.data.hotComments[*].user.nickname')
contentList = jsonpath.jsonpath(jsonData,'$.data.hotComments[*].content')
timeStrList = jsonpath.jsonpath(jsonData,'$.data.hotComments[*].timeStr')
result = list(zip(nicknameList,timeStrList,contentList))
print(result)