引言
知其所以然,是每个明智的开发者都希望掌握的,当然对于有些用一招鲜C-V大法者,相对不是很明智了。因为如果哪天策略变化了,要重新想要找寻真实地址时,就会变得手足无措了。
请开始你的表演
腾讯视频必然是国内最全面,最复杂的视频网站之一了,因此研究他的网页结构很有代表性.
首先,腾讯理所当然不会把视频资源暴露在网页源代码里,所以F12查看他的元素以获得重要信息你会无功而返.
所以,凄凉地研究一段时间后断然放弃...
有一个流传已久的经验, 大概是: 攻克一个网页,最好从移动端入手,至于为什么,
大概因为移动端源代码要稍简单一点, 或者说一些加密算法还不成熟.
所以,get一个小技能, 以为只有我知道, 搜寻了半天居然发现是多数浏览器都支持了n久的...
只是以前是设置参数,现在的浏览器都很智能,一键就可以模拟手机,并且可以选型号
进入正文:
模拟手机浏览器进入视频首页, 任意选择一个视频进入, F12后重新刷新一遍
腾讯不出意料地采取异步加载技术,所以,等n多让人大开眼界的广告加载完毕后,你会看到正片袭来
为了防止不断地动态加载造成打扰,可以等正片加载完毕后停止抓包录制
安心的分析每条代码吧, 有的是图片,有的是css, 特别要留意的是js
要相信在众多的元素里面, 终究可以找到视频播放地址
http://124.14.20.19/vlive.qqvideo.tc.qq.com/z0024zqdzu1.p212.1.mp4?sdtfrom=v1010&
guid=21b1d1487c0e3886a2958dc5f2503b9a&vkey=9644BCB6D0138F9831260BE00AA16EE17DEAAA416155124AA999873279C305
574FB8F0311CA565E95D5CB127925E29683E8813DB6373B64D37F5EBD59EF971B6F32CBE001F0B39B585827D9AC07484FDFD3B1255A95A
550DB69002BF46B20594E6BF36DC67A4F3302ADABA6120CD137D3DA2A049DFD5DDC8&platform=2
有一些参数是不必要的,可以考虑去掉,这里采用尝试的方法,因为的确不懂这些简称什么意思,阅读起来太残忍了
简化后视频地址
http://124.14.20.19/vlive.qqvideo.tc.qq.com/z0024zqdzu1.p212.1.mp4?
vkey=9644BCB6D0138F9831260BE00AA16EE17DEAAA416155124AA999873279C305574FB8F0311CA565E95D5CB127925E29683E8813D
B6373B64D37F5EBD59EF971B6F32CBE001F0B39B585827D9AC07484FDFD3B1255A95A550DB69002BF46B20594E6BF3
6DC67A4F3302ADABA6120CD137D3DA2A049DFD5DDC8
以上可以看到,视频主要参数由 协议http:// + 类似ip + host + vid一样的东西(z0024zqdzu1) + 长串的vkey 组成
需要费心的是vid 和vkey , 主要是vkey,因为其他都能从源代码轻松找到或者拼接
所以找vkey是重点, 不用说,vkey肯定是播放视频的某个关键"钥匙"
需要的vkey在哪里?怎样构造这个奇怪的url?
经过总结发现,构造目标地址方法有三种,
1: 根据规律构造.如页数,每页的个数,其实数
2: 来自某一个文件的一个组成元素, 在第一个文件里找到第二个文件需要的元素,常见于id,cid,vid 等
3: 手动生成, 常见的有时间戳:time.time()
在这个案例中, 方法二比较靠谱.所以,这个vkey就在其他文件中寻寻觅觅吧!
终于,在一个叫getinfo里面发现了可疑文件,他的返回是一长串貌似我们认识的东西
getinfo的完整请求地址
https://vv.video.qq.com/getinfo?callback=txplayerJsonpCallBack_getinfo_552345&&charge=0&vid=z0024zqdzu1&defaultfmt=auto
&otype=json&guid=21b1d1487c0e3886a2958dc5f2503b9a&platform=10201&defnpayver=0&appVer=3.2.26&sdtfrom=v1010&host=v.qq.com
&ehost=https%3A%2F%2Fv.qq.com%2F&sphttps=1&_rnd=1499231532&spwm=2&defn=&fhdswitch=0&show1080p=0&isHLS=0
&newplatform=10201&defsrc=1&_qv_rmt=jBZ5pIl8A19213wFt%3D&_qv_rmt2=o6Qa4YDm149352oVg%3D&_1499231532114=
返回的是一个类json文件,去掉头就是完全的json, 用json解析工具得到如下:
{
"dltype": 1,
"exem": 0,
"fl": {
"cnt": 3,
"fi": [
{
"id": 10203,
"name": "sd",
"lmt": 0,
"sb": 1,
"cname": "标清;(270P)",
"br": 64,
"drm": 0,
"video": 1,
"fs": 4972275,
"sl": 0
},
{
"id": 10212,
"name": "hd",
"lmt": 0,
"sb": 1,
"cname": "高清;(480P)",
"br": 235,
"drm": 0,
"video": 1,
"fs": 16526691,
"sl": 1
},
{
"id": 10201,
"name": "shd",
"lmt": 0,
"sb": 1,
"cname": "超清;(720P)",
"br": 650,
"drm": 0,
"video": 1,
"fs": 31367763,
"sl": 0
}
]
},
"fp2p": 0,
"hs": 0,
"ip": "211.161.248.25",
"ls": 0,
"preview": 139,
"s": "o",
"sfl": {
"cnt": 0
},
"tm": 1499248445,
"vl": {
"cnt": 1,
"vi": [
{
"br": 115,
"ch": 0,
"cl": {
"fc": 1,
"ci": [
{
"idx": 1,
"cs": 16526691,
"cd": "139.690",
"cmd5": "2fa46e4979bef73aeee198b119bcddb5",
"keyid": "z0024zqdzu1.10212.1"
}
]
},
"ct": 21600,
"drm": 0,
"dsb": 0,
"fclip": 1,
"fmd5": "2fa46e4979bef73aeee198b119bcddb5",
"fn": "z0024zqdzu1.p212.mp4",
"fs": 16526691,
"fst": 5,
"fvkey": "771B9BCC38551D087A458F669156E0C8C3E83BE0A8EB9A62C9065A87D1C0A913F43A40BA502ED5BD575A6F66FE66A93E07E2BEAAA48D6997EB610B96AD2436F4AA64134E59CDB1205BF931F801785AA288EFE31242619D391F3F169950BAF5AA0901DA9E8E3B7D81A811FD5348EE8A3FE6046D8C8BE5400A",
"head": 0,
"hevc": 0,
"iflag": 0,
"level": 0,
"lnk": "z0024zqdzu1",
"logo": 1,
"mst": 8,
"pl": [
{
"cnt": 3,
"pd": [
{
"cd": 2,
"h": 45,
"w": 80,
"r": 10,
"c": 10,
"fmt": 40001,
"fn": "q1",
"url": "https://puui.qpic.cn/video_caps/0/"
},
{
"cd": 2,
"h": 90,
"w": 160,
"r": 5,
"c": 5,
"fmt": 40002,
"fn": "q2",
"url": "https://puui.qpic.cn/video_caps/0/"
},
{
"cd": 2,
"h": 135,
"w": 240,
"r": 5,
"c": 5,
"fmt": 40003,
"fn": "q3",
"url": "https://puui.qpic.cn/video_caps/0/"
}
]
}
],
"share": 1,
"sp": 0,
"st": 2,
"tail": 0,
"td": "139.69",
"ti": "《双世宠妃》邢昭林梁洁组坦诚夫妇上演独宠蜜爱",
"type": 1036,
"ul": {
"ui": [
{
"url": "http://124.14.20.19/vlive.qqvideo.tc.qq.com/",
"vt": 203,
"dtc": 0,
"dt": 2
},
{
"url": "http://124.14.20.21/vlive.qqvideo.tc.qq.com/",
"vt": 203,
"dtc": 0,
"dt": 2
},
{
"url": "http://124.14.20.20/vlive.qqvideo.tc.qq.com/",
"vt": 203,
"dtc": 0,
"dt": 2
},
{
"url": "http://video.dispatch.tc.qq.com/35137871/",
"vt": 0,
"dtc": 0,
"dt": 2
}
]
},
"vh": 480,
"vid": "z0024zqdzu1",
"videotype": 2,
"vr": 0,
"vst": 2,
"vw": 848,
"wh": 1.7666667,
"wl": {
"wi": [
]
}
}
]
}
什么标清,高清之类,所幸可以看懂一些了.
而,我们还看到了fvkey, fvkey和vkey一定有着某些不可告人的关系!
并且, 在vl的vi里面的ul里的ui里面有url地址,这url有类ip的东西,所以因电脑而异,需要取出来作为播放页的base_url
所以,getinfo要坚决构造出来,并且得到fvkey, url, 不罢休
那么问题来了,getinfo的url实在超级长,大概有三十多个参数,哪些是需要的呢?
经过苦逼地百次尝试,得出以下结论:
&_1499231532114= 时间戳, 可以去掉,不影响
&_qv_rmt2=o6Qa4YDm149352oVg%3D 比较重点,这是腾讯最近的新技术,对网络起疯狂限速作用,去掉后视频延迟3-5秒出画面,虽加载成功,但是出现明显卡顿
&_qv_rmt=jBZ5pIl8A19213wFt%3D 同上
&defsrc=1 可以去掉,不影响
&newplatform=10201 可以去掉,不影响
&isHLS=0 可以去掉
&show1080p=0 1080p按钮,可以去掉
&fhdswitch=0 全高清切换按钮,可以去掉
&defn= 有人说是清晰度,defn是definition的简写;sd、hd、shd、fhd分别是standard definition、high definition、super high definition、full high difinition的简写。然而,可以去掉
&spwm=2 可以去掉
&_rnd=1499231532 可以去掉
&sphttps=1可以去掉
&ehost=https%3A%2F%2Fv.qq.com%2F 可以去掉
&host=v.qq.com 可以去掉
&sdtfrom=v1010 不能去掉, 延迟加载,播放失败
&appVer=3.2.26 app版本信息,作为后缀便于发送统计的,可以去掉
&defnpayver=0 可以去掉
&platform=10201 平台信息,不能去掉,会导致404
&guid=21b1d1487c0e3886a2958dc5f2503b9a 全球唯一标识符,不建议去掉,画面20s左右开始卡顿
&otype=json 脚本类型,建议保留,便于作json解析,去掉后会展示成xml类型数据
&defaultfmt=auto 像是某个默认按钮,默认为自动,去掉后没有影响, 可以去掉
&vid=z0024zqdzu1 视频唯一标识,显然不能去
&charge=0 应该是付费相关,可以去掉
callback=txplayerJsonpCallBack_getinfo_552345 有待观察,暂时去掉没影响
剩余的base_url: https://vv.video.qq.com/getinfo?
以上是经过了反复对比尝试,挨个增删验证的, 其实有多次爬取经验就会得知一些为0的参数或者默认的参数是可以主动删掉的
本次逐一进行了增删尝试,主要是担心某些参数尽管去掉后不影响最终加载出来,但是可能会导致延迟或者卡顿,这非常影响用户体验
经过梳理,最终获得流畅视频的fvkey和url需要: base_url + vid + otype + guid + platform + sdtfrom + _qv_rmt
那么,这些参数从哪里来?解析一下:
https://vv.video.qq.com/getinfo?可以作为默认base_url
vid可以从视频页面或者源代码中提取
otype为固定的json格式
guid 暂时发现一台机子是固定的,也是限速,可能未必,是微软在作怪
platform固定的
sdtfrom固定的
_qv_rmt 限速技术,难搞, 到处找不到,每次都不一样,先用固定一个试试, 这是该爬虫成败的关键,因为我们认为,抓到一个虽然可以播放但是有瑕疵的视频,即是失败
最后组成了一个可以获取fvkey并且能够比较轻松组装的url, {}便于代码用format方法
https://vv.video.qq.com/getinfo?vid={vid}&otype={otype}&guid={guid}&platform={platform}&sdtfrom=
{sdtfrom}&_qv_rmt=jBZ5pIl8A19213wFt%3D&_qv_rmt2=o6Qa4YDm149352oVg%3D
所以,小黑板画重点了:
首先从播放页得到视频vid
组成getinfo页面,得到fvkey
组成视频真实地址
好吧,实际上也不是什么重点, 因为每个抓取视频网站的爬虫都会经历这些阶段,那么不同在哪里呢?
1:观看了不少爬视频的帖子发现人们常说的getkey(即获取fveky的脚本)在现在的腾讯视频版本没有了,再次证明反爬技术日新月异
2:腾讯视频极有可能在今年上线了新的限制技术, 即前面所说的_qv_rmt, 这个参数由特殊算法生成,每次请求都不一样,每台机子也不一样
猜测可能用了guid和时间戳等数据用一种算法合成,而且成对出现,去掉它的结果就是导致视频加载速度瞬间变成20k左右每秒,几乎一秒一卡,无法观看
如果不去掉它,如何生成呢?
不幸找遍了所有文件,没有找到答案, 所以暂时一成不变了,但是这肯定不是最终解决方案.
所以,有了勉强的源码示例, 但是用一成不变的_qv_rmt值一定时间内没有出问题, 这是一个谜
# 源码示例
import requests
import re
import json
def get_vid(url):
response = requests.get(url)
html = response.text
href = re.search(r'<link rel="canonical" href="(.*?)"',html).group(1)
ht = href.split('/')[-1]
vid = re.search(r'(.*?).html', ht).group(1)
return vid
def get_info_url(vid):
# 默认的参数
json_type='json'
platform = '11001'
guid='ba7f7fab8f8aef2c4ae45883f221c04d'
sdtfrom = 'v1010'
_qv_rmt='703hXQMOA1937593I%3D'
_qv_rmt2='egp3C2aj149060UUA%3D'
# getinfo的base_url
base_info_url = 'https://h5vv.video.qq.com/getinfo?vid={vid}&otype={otype}&guid={guid}&platform=\
{platform}&sdtfrom={sdtfrom}&_qv_rmt={_qv_rmt}&_qv_rmt2={_qv_rmt2}'
# format方法生成getinfo
info_url = base_info_url.format(vid=vid, otype=json_type, guid=guid, platform=platform, \
sdtfrom=sdtfrom, _qv_rmt=_qv_rmt, _qv_rmt2=_qv_rmt2)
return info_url
def get_keys(info_url):
response = requests.get(info_url)
html = response.text
# 正则表达式提取json数据并序列化为json格式
data = re.search('=(.*);', html).group(1)
data = json.loads(data)
for each in data.get('vl').get('vi'):
fvkey = each.get('fvkey')
fn = each.get('fn')
self_host = each.get('ul').get('ui')[0].get('url')
keys={
'fvkey':fvkey,
'fn':fn,
'self_host':self_host
}
return keys
def get_real_url(keys):
# 真实地址的base_url
base_real_url = '{self_host}{fn}?vkey={fvkey}'
# 组装视频真实地址
real_url = base_real_url.format(self_host=keys['self_host'],fn=keys['fn'], fvkey=keys['fvkey'])
return real_url
def main():
url = input('请输入视频链接:')
vid = get_vid(url)
info_url = get_info_url(vid)
keys = get_keys(info_url)
real_url = get_real_url(keys)
print('视频真实地址为:', real_url)
if __name__ == '__main__':
main()
最后,所有的爬虫技术都是针对当前页面的结构进行的,对于一些变化速率很高的网站,比如腾讯视频,抓到的地址很容易失效
这是因为生成key的算法十分复杂, 猜想有guid,时间戳,_qv_rmt等每时每刻都在变化的数据参与计算,目标只有一个:一般人休想永久的搞到地址
这是许多工程师昼夜在研究算法和加密技术的原因.
同时,针对页面的分析,还仅局限于'所见即所得'的状态,爬虫不会无中生有,虽然抓到的地址是裸源无广告,但是很依赖网页的动态加载技术和登陆限制,
也就是说,vip的视频比如只试看5分钟,在不登录前提下,源码中只放出了5分钟,剩余的部分无从找到,
所以还来日方长~