
最近在写Bilibili App的爬虫,由于bilibili是一个视频站,写爬虫很重要的一个环节就是怎样获取到视频的下载地址,所以我把如何获取B站视频下载地址做了一个简单的整理。
获取需要下载视频的av号
一个常见的B站视频的链接如下:
1 | http://www.bilibili.com/video/av1608918/ |
拿到av后面的数字,称为param
1 | param = '1608918' |
获取视频信息
通过抓取B站app发送的HTTP请求,可以知道获取一个视频信息的URL如下:
1 | https://app.bilibili.com/x/v2/view?actionKey=appkey&aid=7725070&appkey=27eb53fc9058f8c3&build=4070&device=phone&from=1&mobi_app=iphone&platform=ios&sign=3fa3c3fa6557094b5680066009b41897&ts=1482977603 |
这个URL参数很多,接下来一一作解释。
- actionKey=appkey
- aid=7725070 param的值
- appkey=27eb53fc9058f8c3 固定
- build=4070&device=phone&from=1&mobi_app=iphone&platform=ios 固定
- sign=3fa3c3fa6557094b5680066009b41897
- ts=1482977603 时间戳
需要我们其他参数都是现成可以获取到的,而sign这个参数是我们需要自己计算得到的,计算方法如下:
(1) 将除sign外的其他参数按升序排列,得:
1 | actionKey=appkey&aid=7725070&appkey=27eb53fc9058f8c3&build=4070&device=phone&from=1&mobi_app=iphone&platform=ios&ts=1482977603 |
(2) 将步骤1的结果与secretKey进行拼接
secretKey的取值(根据appKey来获取):
1 | {"27eb53fc9058f8c3":"c2ed53a74eeefe3cf99fbd01d8c9c375", |
这里secretKey的值是
1 | c2ed53a74eeefe3cf99fbd01d8c9c375 |
得到结果:
1 | actionKey=appkey&aid=7725070&appkey=27eb53fc9058f8c3&build=4070&device=phone&from=1&mobi_app=iphone&platform=ios&ts=1482977603c2ed53a74eeefe3cf99fbd01d8c9c375 |
(3) 计算步骤2中得到的字符串的md5,得到
1 | 3fa3c3fa6557094b5680066009b41897 |
这个值就是sign
经过上面的步骤,我们可以得到获取视频信息的URL,通过GET请求进行访问,会返回json格式的视频信息
1 | { |
由于过于冗杂,这里只截取了一部分。
其中对于视频下载真正有用的是data下面的pages的值:
1 | { |
看得出来这是一个列表,其实b站的CDN上面,一个较长的视频是由几个较短的视频拼接而成,还有另外一种情况就是b站视频的分P,都会使得同一个视频下面存储多个小的视频,pages就是这些小视频的列表,这些视频需要分别获得下载地址,我们关注的参数是每一个子视频的cid。
获取视频的下载地址
下面的链接同样是通过抓取HTTP请求获得:
1 | https://interface.bilibili.com/playurl?device=phone&otype=json&buvid=3168fe38e580b16a02c2cc9beceaf6b7&cid=12662538&appkey=YvirImLGlLANCLvM&platform=iphone&build=4070&quality=2&sign=ae1954356fbd510073f636d9ca2d36e7 |
和上一步一样,对请求参数进行分析:
- device=phone 固定
- otype=json 固定
- buvid=3168fe38e580b16a02c2cc9beceaf6b7 固定
- cid=12662538 视频的cid
- appkey=YvirImLGlLANCLvM 计算方法下面会介绍,但是这个参数其实可以直接固定下来。
- platform=iphone固定
- build=4070固定
- quality=2固定
- sign=ae1954356fbd510073f636d9ca2d36e7 这个值同第二步获取视频信息的sign一样需要计算
appKey的计算方式,下面是object-c代码,十分简单易懂,所以直接贴上来
1 | string check_tv_box(string key, int addsum) { |
appKey的初始字符串为”VsfoFjIDZshujsdt”,累加子为3,返回的out1就是加密后的字符串,即appKey的值,这里是YvirImLGlLANCLvM
sign的计算方式也会用到上面的check_tv_box()函数,下面是计算sign的步骤:
(1) 计算用于拼接的字符串,代码如下:
1 | string sz2 = "zEcQEUTunrHlLvYiGXyefkmJPmDQEtow"; |
算法与计算appKey的算法相同,但是初始字符串为”zEcQEUTunrHlLvYiGXyefkmJPmDQEtow”,累加子为9.得到结果:JNlZNgfNGKZEpaDTkCdPQVXntXhuiJEM
注意:这个结果固定,可以直接用这个值
(2) 将其他所有参数排序
1 | appkey=YvirImLGlLANCLvM&build=4070&buvid=3168fe38e580b16a02c2cc9beceaf6b7&cid=12662538&device=phone&otype=json&platform=iphone&quality=2 |
(3) 在参数最后拼接步骤1的结果:
1 | appkey=YvirImLGlLANCLvM&build=4070&buvid=3168fe38e580b16a02c2cc9beceaf6b7&cid=12662538&device=phone&otype=json&platform=iphone&quality=2JNlZNgfNGKZEpaDTkCdPQVXntXhuiJEM |
(4) 计算步骤3结果的md5,得:
1 | ae1954356fbd510073f636d9ca2d36e7 |
计算出了appKey和sign的值,就可以拼接出获取视频下载地址的URL了。
发送请求可以得到返回的json信息:
1 | { |
其中durl下面的url参数就是视频下载地址了。
写了一个月的第一篇=。=终于写完了
其实工作中碰到过很多app需要抓取信息,但是狠下心来写一篇总结的就只有b站23333
终于是写完了=。=
下一篇依然遥遥无期。。。。