西瓜视频的视频爬取

西瓜视频网站视频爬取

起因

  最近接到产品的一个新需求: 将西瓜视频网站上的视频爬下来,我们内部用来”耍耍”,恩,抱着学习的态度,义不容辞的答应了,嘿嘿嘿。

第一步,搞定主页

  知彼知己乃爬虫实现的第一原则,先打开西瓜主页( https://www.ixigua.com )看看源代码,本以为所有视频都在HTML里面,等我右键查看源码的时候才发现没这么简单,所有的数据全部通过JS异步加载的(代码就不贴了,影响阅读)。自己又不想去看那些加密过的JS代码,怎么办呢?

  看着Chrome浏览器,灵机一动,为何不看看整个页面加载时的网络请求过程呢!!后面的情节就简单了,按F12打开调试模式,点击右边的Network,再刷新下页面,出来了好多的请求,反正页面刷新出数据了,那么请求一定是其中的一个,仔细查找后确认了信使URL( https://www.ixigua.com/api/pc/feed/?min_behot_time=0&category=video_new&utm_source=toutiao&widen=1&tadrequire=true&as=A1B51A73C2D4D2C&cp=5A3234BD92ACFE1 ),通过这个URL拿取数据后,发现是一个JSON字符串,里面包含了主页上要显示的视频信息,大概有标题,图片,视频ID(这个很重要,后面要用到的), 视频访问页面这些信息。

  到这里,主页数据可以说是在我掌控之中了,但是看着这个信使URL,我对as和cp这两个参数产生了兴趣,还是看看人家是怎么构造出来的吧,万一有坑就蛋疼了。查找方法很简单,先查看主页源代码,然后一个个点开它引用的JS文件,再查找”cp”的关键字,很快查到蛛丝马迹了( https://s3b.pstatp.com/toutiao/xigua_video/pc/static/js/vendor.fb60211a255e4c9b884b.js ),大致看了cp的生成逻辑,其中一段很有意思: if(8!=e.length)return{as:"479BB4B7254C150",cp:"7E0AC8874BB0985"};, 既然这样,那我就不客气了,果断将信使URL中的as和cp替换成这两个,发现work fine,那主页入口就是你咯!

第二步,获取视频地址

  主页视频数据中并没有视频的流地址,那先通过视频访问页面看看情况吧,我使用的小白鼠为( https://www.ixigua.com/group/6498538058265133581/ ),访问后查看源代码,果不其然,还是JS异步加载。

  老规矩,使用Chrome开发者工具看网络交互,这次并没有这么顺利,眼睁睁看着页面拿到了视频的地址,并写入到了网页元素的src中,但是在网络交互的数据中并没有看到相关的数据!

  不甘心,一个个请求看,功夫不负有心人,一条请求在我的鹰眼下漏出马脚( https://ib.365yg.com/video/urls/v/1/toutiao/mp4/0b857583f17d4a649cc1c09841ef7126?r=34005713645696556&s=4084222908&callback=tt_playerpjyjm ),该请求的数据中有这么一段: "main_url":"aHR0cDovL3YzLXR0Lml4aWd1YS5jb20vNzg2ZTE1YmYwMmJhNzc4M2FiYmQyMzYyMDViNzAwNzUvNWEzMjUxMTIvdmlkZW8vbS8yMjA3ZDRjZmY5YjE0NjQ0ODU3YTQ2NmI2MDk2YzM2MTg5NzExNTJlNDZmMDAwMGQzZTYxMjU4YjM4MC8=", 命名很耀眼,链接很有气质,这tm不是base64加密么,将这一段加密文本解密,得到url: http://v3-tt.ixigua.com/786e15bf02ba7783abbd236205b70075/5a325112/video/m/2207d4cff9b14644857a466b6096c3618971152e46f0000d3e61258b380/ ,访问一下,恩,可以用。

  再来研究一下我们的解析URL,0b857583f17d4a649cc1c09841ef7126这个就是前面提到的视频ID了,先将它替换成其它视频ID访问下,出错了。。看来后面的参数是保证请求有效的卫士。看来又得去看JS代码了(我是真的不想看加密后的代码。。。),找目标JS文件的方式和前面的方式一样,不再啰嗦,代码看起来很蛋疼,这里有个小技巧,打开一个能格式化JS代码的编辑器,将加密后的JS文件拷贝到它里面,然后格式化一下,代码可读性立马增加不少。

  大致看了下JS代码后,找到核心逻辑:


n.crc32 = function (t) {
var e = document.createElement(“a”);
e.href = t;
var n = function () {
for (var t = 0, e = new Array(256), n = 0; 256 != n; ++n)t = n, t = 1 & t ? -306674912 ^ t >>> 1 : t >>> 1, t = 1 & t ? -306674912 ^ t >>> 1 : t >>> 1, t = 1 & t ? -306674912 ^ t >>> 1 : t >>> 1, t = 1 & t ? -306674912 ^ t >>> 1 : t >>> 1, t = 1 & t ? -306674912 ^ t >>> 1 : t >>> 1, t = 1 & t ? -306674912 ^ t >>> 1 : t >>> 1, t = 1 & t ? -306674912 ^ t >>> 1 : t >>> 1, t = 1 & t ? -306674912 ^ t >>> 1 : t >>> 1, e[n] = t;
return “undefined” != typeof Int32Array ? new Int32Array(e) : e
}(), o = function (t) {
for (var e, o, r = -1, i = 0, a = t.length; i < a;)e = t.charCodeAt(i++), e < 128 ? r = r >>> 8 ^ n[255 & (r ^ e)] : e < 2048 ? (r = r >>> 8 ^ n[255 & (r ^ (192 | e >> 6 & 31))], r = r >>> 8 ^ n[255 & (r ^ (128 | 63 & e))]) : e >= 55296 && e < 57344 ? (e = (1023 & e) + 64, o = 1023 & t.charCodeAt(i++), r = r >>> 8 ^ n[255 & (r ^ (240 | e >> 8 & 7))], r = r >>> 8 ^ n[255 & (r ^ (128 | e >> 2 & 63))], r = r >>> 8 ^ n[255 & (r ^ (128 | o >> 6 & 15 | (3 & e) << 4))], r = r >>> 8 ^ n[255 & (r ^ (128 | 63 & o))]) : (r = r >>> 8 ^ n[255 & (r ^ (224 | e >> 12 & 15))], r = r >>> 8 ^ n[255 & (r ^ (128 | e >> 6 & 63))], r = r >>> 8 ^ n[255 & (r ^ (128 | 63 & e))]);
return r ^ -1
}, r = e.pathname + “?r=” + Math.random().toString(10).substring(2);
“/“ != r[0] && (r = “/“ + r);
var i = o(r) >>> 0, a = location.protocol.indexOf(“http”) > -1;
return (a ? [location.protocol, e.hostname] : [“http:”, e.hostname]).join(“//“) + r + “&s=” + i
}

  这一段代码写的很蛋疼,反正就是根据链接的路径和一个随机参数r去生成参数s的值。核心逻辑有了,r和s的生成自然就容易了,我的目标是用Python实现自动爬取,先是尝试将这段逻辑按照Python的语法转换一遍,但是结果总是不一致,正头疼时候,想到,为啥不直接用Python解释JS代码执行,这样也不用去研究逻辑了,顿时感觉自己贼tm机智。去网上搜了一下,Python还真的有JS执行库:PyExecJS,安装库后,将s和r的生成逻辑代码稍微改一下(去掉其中的DOM操作)放入到库中等待调用,验证了一下,基本无误,最后就是参数中的callback还不清楚怎么填写的,不过影响不大后面再弄,因为这个API已经可以给我吐出视频真实地址了。

总结

  我觉得爬虫最大的乐趣在于和看不见的网页开发者进行攻防的过程,对方防守自己的网站,不让爬虫拿取自己珍贵的数据,而爬虫开发者则为进攻方,为了拿到数据”不择手段”。这个过程有点类似解谜的过程,中途还要转换思维角度,站在网页开发者的角度去思考问题。 对我来说,这次的爬虫行动给我带来了不错成就感和乐趣,我非常享受这种感觉^^。

  Ps:具体的爬虫代码可以去我的github( https://github.com/lecher23 )围观~