Python爬取鬼吹灯2有声小说(PyV8解析js)
偶然在一个网站http://www.ting56.com/ 上面看到有鬼吹灯2的周建龙老师的作品,又不想在电脑上面听,于是就想用python爬下来传到手机上面听。
版本:python2.7.9,win7,用python3的稍微修改下语法吧
首先,找到鬼吹灯2页面http://www.ting56.com/mp3/4704.html
查看页面源码
然后利用re正则表达式提取每集的播放页面的url
现在已经得到每集的播放页面了,在浏览器打开网址http://www.ting56.com/vedio/4704-0-0.html就可以进入播放页面了,按下键盘上的F12键,查看页面的dom树,可以看到播放器的位置对应的dom树中的位置如下:
可以看到,播放器位于dom中的结构层次如下:
<body><div class=”play”><div class=”left”><div class=”bofangqi”><audio>
点开<audio>
可以看到每集资源的网址:
可以看到第一集的网址:
http://audio.xmcdn.com/group16/M03/74/E7/wKgDbFX-nrvhs94WAJNpjNPBR1I503.m4a
对比下前三集的网址
第一集:
http://audio.xmcdn.com/group16/M03/74/E7/wKgDbFX-nrvhs94WAJNpjNPBR1I503.m4a
第二集:
http://audio.xmcdn.com/group12/M03/74/02/wKgDW1X-nyLxOoezAKXvanlGCbQ423.m4a
第三集:
http://audio.xmcdn.com/group11/M09/81/1E/wKgDbVX-nzvgLCC1AKPQpN1m-dg284.m4a
对比可以发现这三个url都没有规律,那么就只有在每集的html中的解析出来
现在查看每集播放页面的html源码
仔细观察就会发现,并没有找到audio标签,说明audio标签是在html文档加载完成之后创建的,或者是在文档的加载过程当中由javascript创建的。于是在html页面寻找和audio有关的script标签,发现没有找到,于是寻找和player有关的标签:
现在回到dom树:
可以发现在audio标签的上面有一个script标签,标签里的内容是:
var param=getAspParas(‘.html’);viewplay()
现在在刚刚打开的js页面中搜索getAspParas,viewplay这两个函数
在viewplay函数中使用了ShowPlay,于是搜索ShowPlay,又发现了m4a,再看看我们的资源的url:
http://audio.xmcdn.com/group16/M03/74/E7/wKgDbFX-nrvhs94WAJNpjNPBR1I503.m4a
发现格式也是m4a,查看ShowPlay函数,可以看到case “m4a”
下面使用了Player_Html5(a,b,c);
于是继续搜索Player_Html5函数
仔细看看上面图片的内容中的Htmls,可以看到这个Htmls字符串的内容就是dom树中的<audio>
标签,这里的资源的url就是Player_Html中的url变量,然后在ShowPlay函数中发现资源url变量是b,再网上层函数viewplay寻找资源url,发现viewplay中是datas[0],但是viewplay函数中并没有传递datas参数,那么datas应该是全局变量,于是在js页面中查看定义的全局变量:
发现并没有找到datas变量,既然在js文件中没有定义,那么应该在html页面中的<script>
标签里有定义,于是在html页面里搜索datas:
果然发现了datas变量,但是这个变量不是直接定义的,而是用FonHen_JieMa函数生成的,于是在js页面里搜索FonHen_JieMa函数:
找到了!看来要想获得资源url,就是要生成datas变量,资源url就是datas[0],所以就在于函数FonHen_JieMa,但是这是javascript函数,直接用python实现还是太麻烦,而PyV8就可以执行javascript函数:
先利用PyV8生成执行javascript脚本:
import PyV8
def get_js_fun():
ctxt = PyV8.JSContext()
ctxt.enter()
ctxt.eval(""" function FonHen_JieMa(u){ var tArr = u.split("*"); var n = tArr.length; var x = ''; for(i=1;i<n;i++){ x += String.fromCharCode(tArr[i]); } return x; } // get url function get_url(u){ x = FonHen_JieMa(u) url = x.split('&')[0] return url } """)
return ctxt.locals.get_url
返回的get_url就可以直接在python中调用了: