前言
有兴趣的童鞋,可以立马抄起python爬网易云音乐的评论了。对于网易云音乐的破解,网上已经有很多现成代码,你们可以直接拿起就用,但这只会让你知其然不知其所以然,下一次换一道题目,你同样不会,还想等着抄答案吗?因为这个网站的反爬极具代表性,我花了好长的时间才搞清楚其中的原理,现在,我在这里详细讲述爬取思路。
爬取分析
1.首先我们打开网易云音乐随便一首歌,第一步,先看翻页逻辑,为什么呢,我发现,比较高端的反爬多半都是AJAX异步为主的,果不然,评论第二页跟第一页的地址是一样的。说的这里,小伙伴可以先去试试。
2.我们先试试能不能拿到数据,比如request的response,或者scrapy的调试模式,你会发现,无论用哪种工具,评论数据都不在网页里。
3.那么我用selenium的page_source呢,同样也是不行。
那么数据在哪呢?
现在我们打开浏览器的fiddler,刷新抓包一下网页
我以chrome举例,你会发现,数据在这个R_SO的XHR里面。
让我们直接调用这个API接口,返回了空白页面。那么我们再来分析这个数据是怎么请求的,切到headers页面,你会发现,这是一个post请求,传入了两个参数,一个是params,一个是encSecKey
这两个参数是什么玩意?怎么来的
先不要急躁,我们先试试,直接传入这两个参数,模仿post请求,是否能得到数据呢?
答案是可以的,感觉我们看到曙光了呢,那么我们再来看看,下一页的params和encSecKey是否有改变。
第一页与第二页params对比:
params:lSONbxzJJ8KQQzhI/6QMsCcDhFeUN7vdFJyvHyl0BEi/W2xUi32cLnkoKjOxTam/zz6r4G2Qyqct/nzc9Sx+BCXX4KGINEpLZBxaw3gOB4YFrOl6BDYvt6AVp2TobZ8KPl3lxAxKu196rJYb8eT2cL2hkb++joxlxoP+y5Xkuqh9FOkGl2WFOSQnCnjs22W7EzroZPb3Co/E3l208+W6nmWKNI9qHOxgiStuWa6gR+g=
params:ZJGaP/tOjowd89zzN5554gR30t9/ZYFTTQQclSpmcwN3fpymcuxQU0iEptA2jSl/STYs474HXE0O9TP/gcBo8Y2uAbC6ux/tkmb/PRm0RyWMgihRqZxMspI1S/oOm2ndLKmUNVc+8kq1IyL+jA6jzol1EMjKEBMvr1m25PARvDKAk3CnUOOXe3j+Tk3PEPFXQxtKDkPIkSMPDDbI9iiQvtrhUCmf/iXQFiN+GeyV34w=
第一页与第二页encSecKey对比:
encSecKey: 39027236d8ad00f00752c1d3773874e652f02fbc172c218ead51327e19b3feaf72fbf75d6e4f3a475e041db273b3ef6cae23feed1c593ffd5842f53bc626078de0cc3466c33d5b4572c464caa79c1fe5302fd7cfaf105dad044dfa16313a8d6d6c541fb18645894f71519064ba6257f5eea87527eea3169955f5bd7a74e4d6bd
encSecKey: 0970b9e51d4e42213b68d8761fdbb8cee06d198fe5500cd8184774d54a4af11058537c2f1671d2231f6cd6f6cf49dfe8c04367adb037552631ea787b453adf08bfaa10bc314b23e43b2c954072d0b6b2ee6d8b629b4de6d93191ba3c0036f039556736d5fbc63f45bcdc84a3b3ca525c51c3dce2d05a04f461d93d7850b5c017
明显不一样,所以我们现在已经明确了问题,如果我们要实现真正的爬取页面,那么其实就是破解这两个参数。
JS源头
这里必须科普一下一个知识,我们之所以能看到五彩纷呈的页面,并不是远程服务器加载好再给我们呈现出来的,而是就像正常的下载文件一样。把服务的js文件下载下来,然后在本地浏览器执行。
这里可能会比较难懂一点,我们先点到之前抓包的R_SO文件,如图操作,找到这个R_SO文件的Initiator
这两个参数,是由这个core c245e96...的JS文件生成的。
我们,现在直接左键点击打开这个JS文件。(在Chrome里面,当你鼠标移到上面,他会显示这个Initiator发起的所有文件,我们现在暂时不知道这两个参数是具体由谁生成的,所以要把所有JS都加载出来)
这是所有的JS,这样子的JS可读性很差,所以我们把这一大段JS Ctrl+A,复制,然后再python里创建JS文件,然后粘贴,然后格式化。
格式化按钮在这
好了,舒服了,接下来,我们再搜索关键字,params和encSecKey,很荣幸,我们找到了这两个关键字所在函数。
接下来,你怎么也必须
突然会看JS了吧,你懂我意思吧
JS破解
现在我们拿到了JS的内容,前面的一大段东西都不是事,重点还是我们破解JS的思路。当我们搜索params的时候,会搜出37个matches。
很好,只有三个,你会发现,里面的JS函数是abcd这种难以阅读的形式,对于我们这种半吊子现学现用的人来说,会更加难以理解,所以必须要从简单的地方入手。这里,我们的切入点就是enSecKey,为什么呢,因为无论你在里面如何修改,最终出口一定是含有params和enSecKey名字的参数,我们切到下面这个enSecKey位置
这里有个data关键字,里面正好是params,和enSecKey。
很大概率,这是这两个函数的出口,我们看看源头,往上面看一下,这是由v0x.bl1x这个函数加载的
来自,那么我们切回去刚刚那个找JS的地方看看。
十有八九就是这个函数。
那么接下重头戏,我们开始阅读这个JS
params和encText都是由bY14p这个函数发起的,上面定义了这个一个BY14p函数,我们先不管windows.asrsea是啥,先看后面的几个参数。
var bYl4p = window.asrsea(JSON.stringify(i0x), bqv4z(["流泪", "强"]), bqv4z(QI7B.md), bqv4z(["爱心", "女孩", "惊恐", "大笑"]));
这里有4个参数,我们称之为第一参数、第二参数、第三参数、第四参数
第一参数:JSON.stringify(i0x)
第二参数:bqv4z(["流泪", "强"])
第三参数: bqv4z(QI7B.md)
第四参数: bqv4z(["爱心", "女孩", "惊恐", "大笑"])
第二个和第四个参数,我们一眼就看得出,这是传入实参,在python里我们也知道,这一定是个定值。不信你们可以去翻阅一下bqv4z的加密方式,不过等等,我们再看第三个参数,QI7B.md是啥,我们去看看
这也是一个实参,那么真相只有一个,那就是第一参数一定是个变化的参数。
这里需要打住,如果我们要继续研究下去,有两种发展思路,一个是阅读JS,破解JS加密重构Python代码。这个难度,就算是学几年爬虫的人估计都不一定达到。第二种,为了不绕进设计者的加密思路中,我们要用另外一种手段取得加密参数,在这里,我介绍第二种方法,因为人家设计者想尽办法让你绕晕,你为什么一定要跟别人的长处较劲呢,于是,我在这里隆重推荐这个抓包工具Charles
Charles的使用介绍比较复杂,你们可以自行去搜索教程安装,有可能我另起一个安装教程,不过简单的来说,就是要你的浏览器安装证书(或者手机)因为Charles默认只支持http,所以你要适当进行设置。Charles怎么说呢,就像是一个中介,在实现服务器和你的电脑端交互的时候,Charles作为中间过滤器给你筛选信息。
好了,我现在就当你准备好。
用Charles我推荐用
火狐浏览器
回到上文,现在,我需要重写JS代码,在不影响整体运行的情况下,我需要知道,传入的这几个参数的运行结果分别是什么
因此,我在这里加入一个alert语法弹出这几个参数的运行结果
#知道你们懒了
alert(JSON.stringify(i0x)+"=="+bqv4z(["流泪", "强"])+"=="+bqv4z(QI7B.md)+"=="+bqv4z(["爱心", "女孩", "惊恐", "大笑"]))
第一步,我们找到JS地址中那个core c245e96...的地址,我们瞧瞧,是在s3.music.126/web/s里面。然后我们打开小叶壶
如果你找不到这个地方,或者显示unknown,不用怀疑,你一定是小叶壶哪里设置出问题了,赶紧去解决吧!
接下来是重点
对着这个core的JS文件,右键,最下面有个Map Local,点开弹出这个界面,把我们修改好的JS文件更改进去,确定。
我们再刷新一下火狐页面
你会发现这几个参数对应的内容都显示出来了,我把原弹框复制出来,然后分割
{"rid":"R_SO_4_478106252","offset":"20","total":"false","limit":"20","csrf_token":""}==010001==00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7==0CoJUm6Qyw8W8jud
我这里给的是第二页的参数,因为第0页第一参数不具代表性,这个东西,只要你做多了你就下意识明白,我也很难说明。
规整化后,你就会发现这几个参数分别是
第一参数:{"rid":"R_SO_4_478106252","offset":"20","total":"false","limit":"20","csrf_token":""}
第二参数:010001
第三参数:00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7
第四参数:0CoJUm6Qyw8W8jud
好了,其实我说到这里,大家就可以接着看网上的破解结果,因为我觉得说到这里已经非常明白了,2、3、4是实参,这些数据不会变,变的是第一个,第一个传入的都是些什么,如果你还没懂,真的枉写那么多爬虫了,接下来该怎么做。网上已经提供了非常多的思路。
这里说漏了个东西,我们还要看windows.asrsea是什么东西,大家搜索关键字,然后在上面可以看到定义的一个变量window.asrsea = d
那么d又是什么鬼
,然后你会发现,d函数返回的就是encSecKey和encText,然后大家要想清楚这个问题,我们在之前定义了windows.asrsea的四个变量,然后他说windows.asrsea = d
那4个变量分别就是对应 d,e,f,g
关于encText,他要的是d,g两个参数,还有个i,当然你问b又是什么,这些我们都不要去管,这一定是某种加密技术,我们现在只需要知道他传入的是什么参数就行。
那么还有一个i,又是啥?
上面定义了,i =a(16)
a又是啥?
a呢,其实就是一个16位长度的随机数
说完,那么encText里面含有什么呢
就是d+g+i
所以encSecKey同理:
params:第一参数 + 第四参数 + 16位长度的随机数
encSecKey:16位长度随机数 + 第二参数 + 第三参数
也就是说encSecKey其实是个常量,随便拷贝一个data里面的数据直接用就完事了。