通过抓包一步到位分析出来的是比较简单的,但某些网站的某个请求中的参数可能是JavaScript计算出来等情况。
比方说我们最常接触的网易云音乐,很多人表示网易云音乐的歌曲热门评论很难抓取,因为请求评论的数据的中的请求参数是经过JavaScript计算加密过的。
而对于这一类的网站,我们通常会有三种情况,对于这几种情况无疑都需要对网页请求的整个流程有比较好的把握,以及能比较有耐心的一层一层分析请求参数等等的来源。
首先按我们看上面的网易云音乐的请求评论数据的参数:params 和encSecKey,同时在Name栏目可以清楚地看到处理该参数的 js 文件为core.js
所以为了弄清楚两个参数的来源,我们把core.js文件下载到本地,使用Javascript在线解压缩 - 在线工具解压缩,得到标准格式的JavaScript文件,搜索两个参数。
我们会发现这两个参数来源于window.asrsea的函数加密,window.asrsea需要四个参数,为了弄清楚这四个参数的来源,我们可以改变本地core.js代码,并用fildder替换执行。
替换之后查看Chrome中的console输出,查看四个参数的值信息,可以看出除了bl其他的几个参数都是固定的字符串值。再看bl值,bl 值由字典构成,总共有五个key值。
rid:rid值由一个固定字符串R_SO_4_和歌曲的id构成
offset:表示当前是第几页的评论数据
total:固定值true
limit:每页显示多少个评论,默认20
csrf_token:无关可以为空
我们知道了参数的来源,弄清楚函数的具体执行流程是什么,一切就豁然开朗了。追踪window.asrsea函数,找到如下内容,现在我们就弄明白了所有的流程了。
既然弄清楚了所有的JS加密流程下面就有几种方法去解决。
1、使用Python模拟
我正常采用的就是这种手段,先分析具体的JavaScript代码,再尝试用Python去模拟,不过这种选择需要你对Python相对比较熟悉。
```python
modulus =‘00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
nonce = '0CoJUm6Qyw8W8jud'
pubKey = '010001'
def aesEncrypt(text, secKey):
pad = 16 - len(text) % 16
text = text + pad * chr(pad)
encryptor = AES.new(secKey, 2, '0102030405060708')
ciphertext = encryptor.encrypt(text)
ciphertext = base64.b64encode(ciphertext)
return ciphertext
def rsaEncrypt(text, pubKey, modulus):
text = text[::-1]
rs = int(text.encode('hex'), 16)**int(pubKey, 16) % int(modulus, 16)
return format(rs, 'x').zfill(256)
def createSecretKey(size):
return (''.join(map(lambda xx: (hex(ord(xx))[2:]), os.urandom(size))))[0:16]
#调用
# 登录加密算法, 基于https://github.com/stkevintan/nw_musicbox脚本实现
def encrypted_id_request(id):
text = {
"c": [json.dumps({"id":id})],
#"csrf_token":"71b6bb13bc2aa7ba1f72afea1730ce50",
}
text = json.dumps(text)
secKey = createSecretKey(16)
encText = aesEncrypt(aesEncrypt(text, nonce), secKey)
encSecKey = rsaEncrypt(secKey, pubKey, modulus)
data = {
'params': encText,
'encSecKey': encSecKey
}
return data
```
( 对createSecretKey 的解释见 https://www.jianshu.com/p/30e6b6fa28fd )
(对AES加密 JavaScript和 python端的应用 见 http://outofmemory.cn/code-snippet/35524/AES-with-javascript-java-csharp-python-or-php )
2、Python执行JavaScript代码
Python执行JavaScript代码,如果对Python不是很熟悉,建议采用这种方法,这种方法的可用第三方库比较多,研究了一些文档之后发现:
ScriptControl只能在windows上运行,需要win32com库
PyV8能在windows和*nix上运行,需要装PyV8库
SpiderMonkey是mozilla的js引擎在python上的移植。
经评论区的朋友们提醒,自己也尝试使用了一下另外一个第三方库:Js2Py
此第三方库不但可以执行JavaScript代码,甚至可以把JavaScript代码转换成Python代码,但是在此只推荐转换简单的JavaScript代码,这是一个转换的案例。
由于网易云音乐的评论加密这一块涉及的函数相对较多,这里不推荐使用Python执行JavaScript代码。
3、最粗暴的方法
最粗暴的方法是使用selenium+phantomjs无界面浏览器,这两者的结合其实就是直接操作浏览器,可以获取JavaScript渲染后的页面数据。
这两者结合使用的缺点:
由于是无界面浏览器,采用此方案效率极低,如果大批量抓取不推荐。
对于异步请求并且数据在源码中并不存在的,同时也就无法抓取到的数据。
对这两个不了解可以查一下两者的官方文档,也可以读读这篇文章快都上手:python爬虫的最佳实践(五)--selenium+PhantomJS