从cctv网页版flash提取视频链接
cctv网页版到现在还是主要用flash播放视频,而chrome浏览器用flash比较麻烦,所以我花了点时间研究一下cctv的flash是怎么下载视频的。首先,要知道flash下载的数据,用chrome和firefox的开发人员面板的Network页的XHR或者Media标签是看不到的,因为flash是自己独立地处理数据和播放视频的。
用IE10或以上浏览器,打开这个链接http://tv.cctv.com/2018/04/01/VIDEYI7D9VFtnbOjIeIP4Pcn180401.shtml,然后打开开发人员工具,点开网络标签,点开始捕获,再刷新页面。
首先根据类型是application/x-shockwave-flash,看到flash的引用是http://player.cntv.cn/standard/cntvplayerQC20181126.swf?v=0.171.5.8.9.6.3.5.2,这个链接不是根据视频地址变化而变化的。
继续往下面找,看到很多video/MP2T的标签,这个是ts流媒体文件的类型,所以在以上两行记录之间的其他行里继续找由Flash发起的请求,就看到了http://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?,而且接收大小有10.6KB,跟我们平常见到index.m3u8文件大小差不多。
就打开看看吧。双击那一行,选择“响应正文”标签,一看,应该是个json文件,有很多mp4的链接。
全选这段文本,复制到json在线格式化的网站。我们看到有mp4链接,有m3u8链接。
别着急,在开发面板继续找,找到了application/x-mpegURL类型,是m3u8文件。可以看出,1200应该指码率。见图片1的红框
我们在json格式化页面直接搜索以下文本:“http://hls.cntv.lxdns.com/asp/hls/1200/0303000a/3/default/dff2ea4f955f4e5283cd61d7e5e6dc82/1200.m3u8”,是找不到对应结果的,但是有一个hls_url是"http://hls.cntv.lxdns.com/asp/hls/main/0303000a/3/default/dff2ea4f955f4e5283cd61d7e5e6dc82/main.m3u8?maxbr=2048",与前者比较像,我们把后者用浏览器打开,下载的文件里就有对应码率1200的链接。我们以后要下载的话,就按浏览器播放视频用的1200码率下载就好了。
在开发面板双击上述1200.m3u8的一行,看“响应正文”,是一个标准的m3u8文件,其中每个文件名N.ts是要接在“http://hls.cntv.lxdns.com/asp/hls/1200/0303000a/3/default/dff2ea4f955f4e5283cd61d7e5e6dc82/”后面的。m3u8文件主要有两种描述路径的格式,因为这里是较简单的一种,所以就不提及较复杂的那一种了。
所以现在重点回到了getHttpVideoInfo.do参数的分析。完整的url是"http://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid=dff2ea4f955f4e5283cd61d7e5e6dc82&tz=-8&from=000news&idl=32&idlr=32&modifyed=false&url=http://tv.cctv.com/2018/04/01/VIDEYI7D9VFtnbOjIeIP4Pcn180401.shtml&tsp=1598349127&vn=1540&vc=3204F3DC432A4C0DE9C770BE00B8ED93&uid=C2BD12DEC005F94C4858A92ED76D622D",这么长,哪些参数是可以舍弃的呢?到现在大家都应该对"dff2ea4f955f4e5283cd61d7e5e6dc82"这个重复出现的文本比较有印象了。于是我们大胆求证,用浏览器访问http://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid=dff2ea4f955f4e5283cd61d7e5e6dc82,就能获取到了带hls_url的json。(谢谢cctv的程序员)当然,要读懂json还是要有一点编程基础的。
然后在网页正文里搜索“dff2ea4f955f4e5283cd61d7e5e6dc82",能搜索到两个结果。这样我们只需要用正则表达式匹配而获取guid就可以了。
以下用Ruby代码示例。
在网页<head>标签看到用utf-8编码。我们先把网页的裸html用脚本下载下来,可以搜索到var guid这一个语句。所以不用另外下载其他js脚本。
require 'open-uri' require 'json' Header = { 'User-agent' =>'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36', } def download(link) return URI.open(link, Header).read end # 以后者为示例,运行命令: ruby cctv.rb cctv链接 link1 = (ARGV[0] || 'http://tv.cctv.com/2018/04/01/VIDEYI7D9VFtnbOjIeIP4Pcn180401.shtml') html = download(link1) # 获取视频guid test = /var\sguid\s=\s"(.*?)"/.match(html) raise "找不到guid" if (test == nil) guid = test[1] # 获取m3u8列表 json = download("http://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid=#{guid}") hls_url = JSON.load(json)['hls_url'] # 注意某些特殊字符可能导致json解析失败 hls_url.gsub!('main', '1200') # 替换码率为'1200' hls_url = hls_url[0, hls_url.index('?')] # 去除 '?maxbr=2048' m3u8 = download(hls_url) File.write("#{guid}.m3u8", m3u8) # 开始下载ts文件 lines = m3u8.split(/\r|\n/) lines.select{|x| x[0] != '#'}.each do |line| fn = line link = hls_url.sub('1200.m3u8', fn) bin = download(link) File.open(fn, 'wb') do |fio| fio.print bin end print '.' sleep(rand(2)) # 限制下载的频率 end puts '', "生成命令: ffmpeg -i #{guid}.m3u8 -c:v copy -c:a copy result.mp4" # 重要说明,用ffmpeg直接处理m3u8文件,仍有可能导致合并后的视频文件出现错乱、卡屏现象,这个问题我不知道是什么回事。