ruby爬取cctv的flash视频


从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文件,仍有可能导致合并后的视频文件出现错乱、卡屏现象,这个问题我不知道是什么回事。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM