爬虫小白在b站看的视频教程,爬取的是网易云音乐的歌曲热评。本文仅用于学习记录,不用作任何商业用途。本文最后附带源代码和运行效果图。
1.安装库
import requestsfrom Crypto.Cipher import AESfrom base64 import b64encodeimport json
这里有一个小坑,就是这个Crypto。如果电脑中的site-packages中已经带有crypto的话,先把它删除!然后我们再通过pip install pycryptodome来安装到Crypto。
2.打开,随便打开一首歌。按F12进入开发者模式,使用Network,勾选Preserve log,刷新,抓包。找到get?csrf_token?,点击搜集信息。
这里可以看到data中的params和encSecKey已经进行了加密。
点击Preview,可以看到hotComment就在这里!所以我们需要找到原来的data并模拟加密过程,才能得到热评数据。
刷新页面,点开后面的initiator选项。
点击左下角的大括号。
在3516行这里设置断点。
刷新页面。这时我们需要观察右边的url是否为:
'/weapi/comment/resource/comments/get?csrf_token='。
如果不是的话,就点击中间那个按钮,直到找到与上面这个相同的网址。
几次点击之后,我们就找到了这个网址。
观察data,不是我们原始的。
点击call stack。
根据经验,原始data应该在这个里面。点开它。
然后把call stack锁起来,查看scope。这里面有很多信息。
bWf1x就携带着加密后的数据。而i7b携带的就是未加密的原始数据。
我们需要将i1x的数据保存起来。
然后我们看window.asrsea这个函数,它后面带着4个参数。
i7b就是原始数据;后面三个数据我们可以在控制台中运行查看结果。
这几个参数结果都保留下来。
点击window.asrsea函数,然后我们看d这个函数。
在13182这里设置一个断点。然后点击蓝色按钮一下。
然后看右边的Scope,我们把i和encSecKey的结果保留下来。
看这里的encSecKey,是由c函数得到的。而i是由a(16)得到。
a(16)产生的是一个随机的16位字符串。
所以i是一个随机的16位字符串。一旦这个i确定下来,由于e和f是固定的,
所以得到encSecKey也是固定的。
这里的关系就是:随机得到一个i,然后运行c函数,就可以得到一个encSecKey;只要i不要,encSecKey就是不变的。
好了,现在我们就剩下最后一个encText需要获得了。它与b函数有关。
然后看到b函数,我们只需要把b函数用代码写出来就好了。
def to_16(d):pad = 16 - len(d) % 16d += chr(pad) * padreturn ddef enc_params(d, key):aes = AES.new(key=key.encode('utf-8'), IV=iv.encode('utf-8'), mode=AES.MODE_CBC)d = to_16(d)bs = aes.encrypt(d.encode('utf-8'))return str(b64encode(bs), 'utf-8')def get_params(d): # 必须模拟加密过程first = enc_params(d, g)second = enc_params(first, i)return second
最后,我们将获得的encSecKey和get_params()函数放入到data中去。
通过requests.post(url, data)去请求响应,
通过.json()获取数据。
data = {'params': get_params(json.dumps(d)),'encSecKey': get_encSecKey()}response = requests.post(url, data=data)json = response.json()n = 0for hotComment in json['data']['hotComments']:print(n, hotComment['content'])n += 1
最后将热评打印出来。可以看到和网页上的热评是一样的,爬取成功!
最后这里附上所有的源代码,只要点击运行即可输出这首歌的热评。
如果想要获取到其他歌曲热评的话,需要找到它对应的rid和threadId。这个我还没想到如何自动获取,大家可以在评论区留言讨论。
import requestsfrom Crypto.Cipher import AESfrom base64 import b64encodeimport jsonurl = '/weapi/comment/resource/comments/get?csrf_token='d = {'csrf_token': "",'cursor': "-1",'offset': "0",'orderType': "1",'pageNo': "1",'pageSize': "20",'rid': "R_SO_4_118261",'threadId': "R_SO_4_118261"} # 不同的歌曲需要更改d里面的rid和threadId.而rid等于threadId.e = "010001"f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"g = "0CoJUm6Qyw8W8jud"i = "Jq1AsJXHNQhhp3Kr" # 随机(i决定了encSecKey; 固定了i也就固定了encSecKey)encSecKey = "99b85187afa87a4a289fb1db9736254a2931121e22484ad238e659bb07117479eac65c5e6bfe6de6c4875478196b814ef5b4284330d7815f3a8c91b7533cc716d09af6232ba40ff9ad5592bb833eb870048b096af88f88d61de016351bcb4e3193a1791829485dcf5fb17d34f6abcfdaaa3e5c7eeff3d39ca50807dea90273c2" # 随机iv = "0102030405060708"def to_16(d):pad = 16 - len(d) % 16d += chr(pad) * padreturn ddef enc_params(d, key):aes = AES.new(key=key.encode('utf-8'), IV=iv.encode('utf-8'), mode=AES.MODE_CBC)d = to_16(d)bs = aes.encrypt(d.encode('utf-8'))return str(b64encode(bs), 'utf-8')def get_params(d): # 必须模拟加密过程first = enc_params(d, g)second = enc_params(first, i)return seconddef get_encSecKey():return encSecKeydata = {'params': get_params(json.dumps(d)),'encSecKey': get_encSecKey()}response = requests.post(url, data=data)json = response.json()n = 0for hotComment in json['data']['hotComments']:print(n, hotComment['content'])n += 1