使用 ruby 下载 youtube 视频以及字幕

来源:互联网 发布:淘宝小号用什么注册 编辑:程序博客网 时间:2024/04/30 14:20


最近喜欢上了 Ruby,非常神奇,所以一直想用它做些什么!

正好女朋友想学些专业英语,就去youtube 上翻了一下,有很多呀,关键还有字幕大笑

只不过直接在网页上看不是很方便,字幕离视频太远了,看字幕看不到视频,看视频有看不到字幕;

用了代理,虽然看着不卡,但是视频太模糊了,所以决定自己下载他高清版本的视频在电脑上看。

正好拿 Ruby 再练一次手,上次用Ruby 登陆新浪微博用的也挺好的,哈哈

要做的有三步:

1:下载视频,网上搜的大部分已经不适用了,不过youtube 获取 flv 的格式没有大变

2: 下载字幕文件,并转换成 srt 字幕格式


因为刚学 Ruby 很多 Ruby 的高级功能没用,所以基本还是当平常的语言用的,比如每个函数有都要用return 才安心!

呵呵,慢慢学着改吧吧!

里面包含了 cookie.rb 这个事自己原来写新浪微博登录的时候用到的,这里其实也用不到,直接去掉就可以了!


因为众所周知的原因 youtube 在中国是不能直接访问的,所以需要使用socket 代理

类中:

[ruby] view plaincopy
  1. @ProxyAddress='192.168.0.56'  
  2. @ProxyPort=7777  

是定义代理地址的,如果 @ProxyAddress 为 nil 则不适用代理!

另外 socksify 可能需要使用 gem 安装


直接贴代码了:

[ruby] view plaincopy
  1. require 'net/http'  
  2. require 'uri'  
  3. require 'cgi'  
  4. require 'socksify/http'  
  5. require 'json'  
  6. require 'rexml/document'   
  7.   
  8. require_relative '../lib/cookie'  
  9. class RstTime  
  10.     def initialize(sec)  
  11.         @sec = sec.to_f  
  12.     end  
  13.     def Time   
  14.         tsec = @sec.to_i  
  15.         #puts tsec.to_s  
  16.         ms = @sec - tsec  
  17.         ms = (ms * 1000).to_i  
  18.   
  19.         sec = tsec % 60  
  20.         tsec /= 60  
  21.   
  22.         minute = tsec  % 60  
  23.         tsec /= 60  
  24.   
  25.         hour = tsec   
  26.   
  27.         sprintf("%02d:%02d:%02d,%03d",hour,minute,sec,ms)  
  28.     end  
  29. end  
  30. class YoutubeVideo  
  31.     def initialize page_uri  
  32.         @ProxyAddress='192.168.0.56'  
  33.         @ProxyPort=7777  
  34.         @cookies = Cookie.new()  
  35.         @UserAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20100101 Firefox/14.0.1'  
  36.         @VideoUri = URI.parse page_uri  
  37.         @UriPars = CGI.parse(@VideoUri.query)   
  38.         if @UriPars.has_key?('v')  
  39.             @VideoID = @UriPars['v'].first  
  40.         end  
  41.     end  
  42.     def IsValid  
  43.         return @VideoID != nil  
  44.     end  
  45.     def DownloadFile(url ,saveto)  
  46.         uri = URI(url)  
  47.         writetotal = 0  
  48.         saveto = saveto.gsub('/','-')  
  49.         Net::HTTP.SOCKSProxy(@ProxyAddress@ProxyPort).start(uri.host, uri.port) do |http|  
  50.             request = Net::HTTP::Get.new uri.request_uri  
  51.             http.request request do |response|  
  52.                 open saveto, 'w' do |io|  
  53.                     response.read_body do |chunk|  
  54.                         writetotal += chunk.length  
  55.                         io.write chunk  
  56.                     end  
  57.                 end  
  58.             end   
  59.         end  
  60.         return writetotal  
  61.         #open(saveto, "wb") do |file|  
  62.             #file.write(res.body)  
  63.         #end  
  64.     end  
  65.     def DownloadVideos()  
  66.         index = 0;  
  67.         #puts JSON.pretty_generate(@downloadUrl)  
  68.         downloadto = @title.first + ".flv"  
  69.         @downloadUrl.each do |x|  
  70.             puts "download video:" + downloadto  
  71.             break if DownloadFile(x,downloadto) > 0  
  72.         end  
  73.     end  
  74.     def DownloadLyrics()  
  75.         return if @lyricUrl == nil  
  76.         lyric = @title.first + ".flv.srt"  
  77.         res = HttpGet(@lyricUrl+'&type=track&lang=en&name&kind=asr&fmt=1')  
  78.         doc = REXML::Document.new(res.body)  
  79.         index = 1  
  80.         lyric = lyric.gsub('/','-')  
  81.         open lyric, 'w' do |io|  
  82.             doc.elements.each('transcript/text'do |ele|  
  83.                 start = ele.attributes['start'].to_f   
  84.                 starttime = RstTime.new(start)  
  85.                 endtime = RstTime.new(start + ele.attributes['dur'].to_f)   
  86.                 io.write index.to_s + "\n"  
  87.                 io.write starttime.Time + ' --> ' + endtime.Time  + "\n"  
  88.                 io.write ele.text    
  89.                 io.write "\n"  
  90.                 io.write  "\n"  
  91.                 index += 1  
  92.             end  
  93.         end  
  94.     end  
  95.     def ParseVideoUri()  
  96.         return nil if @VideoID == nil  
  97.         infoUri = "http://www.youtube.com/get_video_info?video_id=#{@VideoID}&el=detailpage"  
  98.         res = HttpGet(infoUri)  
  99.         return nil if res.code == 200  
  100.         @videoPars = CGI.parse(res.body)  
  101.         @url_encoded_fmt_stream_map  =CGI.parse(@videoPars['url_encoded_fmt_stream_map'].first)  
  102.         @rvs =CGI.parse(@videoPars['rvs'].first)  
  103.         #puts @url_encoded_fmt_stream_map  
  104.         @videoPars.delete('url_encoded_fmt_stream_map')  
  105.         @videoPars.delete('rvs')  
  106.         @title = @videoPars['title']  
  107.         #puts @url_encoded_fmt_stream_map['url'].class   
  108.         @downloadUrl =  @url_encoded_fmt_stream_map['url']   
  109.         @signs = @url_encoded_fmt_stream_map['sig']  
  110.         @downloadUrl.each_index do |x|  
  111.             @downloadUrl[x] = @downloadUrl[x] + '&signature=' + @signs[x]  
  112.         end  
  113.         @lyricUrl = @videoPars['ttsurl'].first  
  114.     end  
  115.     def HttpGet(url,limit=10,hdrs=nil)  
  116.         raise ArgumentError, 'too many HTTP redirects' if limit == 0  
  117.         uri = URI(url)  
  118.         ck = @cookies.GetDomainCookie(uri.host)  
  119.         req = Net::HTTP::Get.new(uri.request_uri)  
  120.   
  121.         req['User-Agent'] = @UserAgent  
  122.         if hdrs != nil   
  123.             hdrs.each do |key,val|  
  124.                 req[key] = val  
  125.             end  
  126.         end  
  127.         req['Cookie'] = ck if ck != nil  
  128.         if @ProxyAddress != nil   
  129.             #puts @ProxyAddress + ':' + @ProxyPort.to_s  
  130.             res = Net::HTTP.SOCKSProxy(@ProxyAddress@ProxyPort).start(uri.host, uri.port) do |http|  
  131.                 http.request(req)  
  132.             end  
  133.         else  
  134.             res = Net::HTTP.start(uri.host, uri.port) do |http|  
  135.                 http.request(req)  
  136.             end  
  137.         end  
  138.         @cookies.SaveCookie(uri.host,res.to_hash['set-cookie'])   
  139.         if res.kind_of?(Net::HTTPRedirection)   
  140.             newurl = res['location']   
  141.             newurl = newurl.sub(/^\//,'http://'+uri.host+'/')  
  142.             HttpGet(newurl,limit-1)   
  143.         end  
  144.         return res  
  145.     end  
  146. end  
  147.   
  148. if __FILE__ == $0  
  149.     exit if ARGV[0] == nil  
  150.     exit if ARGV[0].length == 0  
  151.     #yv = YoutubeVideo.new('http://www.youtube.com/watch?v=DC-pQPq0acs&feature=b-vrec');   
  152.     #yv = YoutubeVideo.new('http://www.youtube.com/watch?v=dtjrJr1oNmo');   
  153.     yv = YoutubeVideo.new(ARGV[0])  
  154.     if yv.IsValid() == false   
  155.         puts "Invalid url:" + ARGV[0]  
  156.         exit  
  157.     end   
  158.     yv.ParseVideoUri()   
  159.     yv.DownloadVideos()   
  160.     yv.DownloadLyrics()   
  161. end 
0 0
原创粉丝点击