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