网易云热评评论爬取
一,分析页面
首先,我们还是得对这个页面进行一个分析,由于对页面的观察可知,此评论的抓取应该是一个动态加载,所以我们直接选择Fetch/XHR
在这里我们可以发现我们需要爬取的精彩评论的数据存在于hotComments里面,因此,我们确定了在这里可以找到我们需要的数据
一开始,还没发现有这么难得获取数据,直接想当然的写代码,结果发现并没有爬取到精彩评论,但是最新评论倒是出来了,代码如下:
import json
import requests
class music_data(object):
def __init__(self):
self.url = "https://music.163.com/weapi/comment/resource/comments/get?csrf_token="
self.headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
}
def data_get_index(self):
data = {
"params": "B8xoi2aSllQrXAzBzrlGnhAssKhSNEjs0/KutlJ2LlQfoZR1lnKy+ROPqVidcI9mWv42rV2RM0a2qjxF3im37cIoCosYScsOljIpFJ1p5BOgPxXEAGevLMPy4uz4tTxnRYh39yp8GIvUeY2xLEDo4Lvx0vnSimt+6e3BgCOHUSAXOEoiZeVgBx+Pw/R/wgGigtyiyDOpg+iQLnyYZAM+eWQwyHpnFYlrZ48cf1lSIfaOHMQSEnQmQgOMBpsVhgua1mUHHDlS/J7AiXVRXONg81Lm6H/RFYwcYzLnjR/Wmio=",
"encSecKey": "d150eb431642a10291127dcf395d5b77f14d6e72f9f7f6d87922cbefc7796b842ecec500d0bfe5a50ec035d590a839ad384e325065f678d53268cc703205c58a6dcb8281906acda0af72e1a3769b656a0abf2abc69111b3ed0542ab1fd1e7a3ed875fdc72f343ecb505b1a9838f8a7a3c9ab8a78364201c52772d4fb3bd63537"
}
response = requests.post(url=self.url, headers=self.headers, data=data)
dict_data = json.loads(response.text)["data"]["comments"]
# print(dict_data)
for data in dict_data:
title = data["content"]
print(title)
if __name__ == '__main__':
music = music_data()
music.data_get_index()
当然上述代码,仅仅只是获取到了最新评论,并未获取到精彩评论,因此,我们需要接着对当前页面进行一个分析。
由于这个是栈的模式,所以我们直接点击第一个,从第一个逐步往下点击查看
在这里,我们可以看出,这里是需要发送一个东西,因此,初步怀疑这里可能是我们需要的数据信息
在这里,发现现在还是处于一个加密状态 ,因此,我们需要接着debug一下。
发现这个可能是评论的url地址,接着往下分析
我们发现了这个可能就是我们需要获取到的一个表单信息。
接着我们还需要去找到对应的一些函数,框架如下:
!function() {
function a(a) {
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);
return c
}
function b(a, b) {
var c = CryptoJS.enc.Utf8.parse(b)
, d = CryptoJS.enc.Utf8.parse("0102030405060708")
, e = CryptoJS.enc.Utf8.parse(a)
, f = CryptoJS.AES.encrypt(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)
}
function d(d, e, f, g) {
var h = {}
, i = a(16);
return h.encText = b(d, g),
h.encText = b(h.encText, i),
h.encSecKey = c(i, e, f),
h
}
function e(a, b, d, e) {
var f = {};
return f.encText = c(a + e, b, d),
f
}
window.asrsea = d,
window.ecnonasr = e
}();
当然,我们还需要找到对应的函数然填进去,一下是我在分析过程中用到的数值。
"csrf_token": "",
"cursor": "-1",
"offset": "0",
"orderType": "1",
"pageNo": "1",
"pageSize": "20",
"rid": "A_PL_0_919620061",
"threadId": "A_PL_0_919620061"
var bVg5l = window.asrsea(JSON.stringify(i3x), bsk0x(["流泪", "强"]),
bsk0x(WH9y.md), bsk0x(["爱心", "女孩", "惊恐", "大笑"]));
这里这个相当于bVg5l = window.asrsea(JSON.stringify(d), e,f,h),
https://music.163.com/weapi/comment/resource/comments/get?csrf_token=
d: "{\"csrf_token\":\"\"}"
d = data
e: "010001"
f: "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
g: "0CoJUm6Qyw8W8jud"
i: "kDUryOwaF2Zu3GsO"
encSecKey: "1bf4f437583262d1998f982942bb085ae69e3a9affc78e64b4d407065058a02844b2515eaf62db34c56a87e17b800535e21697d7a88f6d01cb7c06d0ae75e31fc10ed3cf7dbe641a6bd23a3db40e928ce317b28359857f808257f2bc38b1cf3f134ea81f556e4035fe49d7c7b7fd31172475ef47dd6dd340f0448ab543b87e44"
二,实战
根据以上的信息,我们可以直接开始抒写代码,注意这里可就不是get请求了,而是post请求。
实战之前,我们还需要了解一下Crypto这个库。Crypto.Cipher
是一个加密解密库,而AES
是一种对称加密算法。
在这里,我们用一段示例代码来展示其作用
from Crypto.Cipher import AES
# 创建一个AES对象,指定密钥和加密模式
key = b'Sixteen byte key'
cipher = AES.new(key, AES.MODE_ECB)
# 要加密的数据
data = b'This is a secret message.'
# 对数据进行加密
encrypted_data = cipher.encrypt(data)
print("Encrypted data:", encrypted_data)
# 创建一个AES对象,指定密钥和解密模式
cipher = AES.new(key, AES.MODE_ECB)
# 对加密后的数据进行解密
decrypted_data = cipher.decrypt(encrypted_data)
print("Decrypted data:", decrypted_data)
上面的示例中,我们首先创建了一个AES
对象,并指定了密钥和加密模式。然后,我们使用该对象对数据进行加密,并将加密后的数据打印出来。接下来,我们再次创建了一个AES
对象,并指定了相同的密钥和解密模式。最后,我们使用该对象对加密后的数据进行解密,并将解密后的数据打印出来。
请注意,上述示例中的密钥长度必须是16字节(128位),因为AES算法要求密钥的长度为128位、192位或256位。
获取精彩评论代码如下:
from Crypto.Cipher import AES
from base64 import b64encode
import requests
import json
data = {
"csrf_token": "",
"cursor": "-1",
"offset": "0",
"orderType": "1",
"pageNo": "1",
"pageSize": "20",
"rid": "R_SO_4_411214279",
"threadId": "R_SO_4_411214279"
}
d = data
e = "010001"
f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
g = "0CoJUm6Qyw8W8jud"
i = "kDUryOwaF2Zu3GsO"
def Get_encSecKey():
return "1bf4f437583262d1998f982942bb085ae69e3a9affc78e64b4d407065058a02844b2515eaf62db34c56a87e17b800535e21697d7a88f6d01cb7c06d0ae75e31fc10ed3cf7dbe641a6bd23a3db40e928ce317b28359857f808257f2bc38b1cf3f134ea81f556e4035fe49d7c7b7fd31172475ef47dd6dd340f0448ab543b87e44"
def Get_encText(data):
first = enText(data, g)
second = enText(first, i)
return second
def to_16(a):
size = 16 - len(a) % 16
return a + size * chr(size)
def enText(a, b):
iv = "0102030405060708"
a = to_16(a)
aes = AES.new(key=b.encode("utf-8"), mode=AES.MODE_CBC, iv=iv.encode("utf-8"))
bs = aes.encrypt(a.encode('utf-8'))
return str(b64encode(bs), "utf-8")
url = "https://music.163.com/weapi/comment/resource/comments/get?csrf_token="
resp = requests.request(url=url, method="POST", data={
"params": Get_encText(json.dumps(data)),
"encSecKey": Get_encSecKey()
})
str = resp.content.decode()
dic_json = json.loads(str)
hotComments = dic_json["data"]["hotComments"]
with open("hotcomments.txt", "w", encoding='utf-8') as file:
for i in hotComments:
file.writelines(i["content"] + "\n")
print("over!")
resp.close()
file.close()
结果如下: