`
ruanqi
  • 浏览: 25595 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

编写ruby脚本批量下载《老友记》全集(mp3文件)

阅读更多

《老友记》是美剧中的经典,其中的对白也早已成为英语爱好者的宝典,我当然也是粉丝之一啊。前几天在普特英语网 上发现有所有10季老友记的对白mp3文件下载 ,大喜!!可惜每一集的连接都在不同的页面上,难道要我保存200多次?! 当然不行,200多次重复机械劳动太丢人啦!而且普通英语网上还有好多不错的英语资料呢,还是写个脚本批量下载的好。 好了,这就开始!

我的ruby 版本是1.8.6 ,这个版本在下载较大文件时会出现问题 ,后面会提到啦。为了吸引眼球,我还是先把结果的截图放到前面来咯

 

ps:一共是10季嘛


 

ps:这个是第四季的全部对白

 

步骤:

   1.找到所有包含老友记对白的页面url,

   如"http://www.putclub.com/article.php?articleid=8761 "

   2.找到这个url中的《老友记》的mp3文件,以及对应的标题,

   如上面这个url中的mp3文件是"http://listen.putclub.com/resource/lessons/liurenxing/liurx/12.mp3 ",

   标题是 六人行1-12The One With the Dozen Lasagnas

   3.根据标题确定该对白属于第几季,

   如"六人行1-12 The One With the Dozen Lasagnas"是第1季12集

   4.开始批量下载《老友记》对白文件,将每一季的对白下载到对应的文件夹下,

   如第5季的对白下载到/friends/season-5/

 

 

code:

                                                                                                                                                                  

 

   步骤1 ,(这个很简单,因为普特英语网上的文章的url就是http://www.putclub.com

    /article.php?articleid=XXXX ,老友记的XXXX就是从87498976 ,哈哈,天助我也!)

 

def get_urls_in_putclub(url_prefix,start_index, end_index)
  page_count = end_index - start_index + 1
  urls = []
  index = start_index
  page_count.times do 
    url = url_prefix + String(index)
    urls << url
    index += 1
  end
  urls
end

    调用

all_urls = get_urls_in_putclub("http://www.putclub.com/article.php?articleid=",8749,8976)

    就得到了所有urls;

                                                                                                                                                                  

 

    步骤2 ,这个步骤要得到HTML中的对白标题mp3文件 连接,用正则表达式来把她们scrape下来

 

     标题的html格式是这样子滴:

 

.......
<div class="subhead">
<b>六人行1-12The One With the Dozen Lasagnas </b>
</div>
......

    对应的匹配方法是这样子滴:

 

def scrape_resource_title(html)
  %r{<div\s*class=[',"]?subhead"\s*><\s*b\s*>\D*(.*?)</b\s*>}mi =~ html
  $1
end

    返回的标题就是'1-12The One With the Dozen Lasagnas'

 

     mp3文件连接的html格式是这样子滴:

 

......
<p align="center">
<a href="http://listen.putclub.com/resource/lessons/liurenxing/liurx/12.mp3">下载地址</a>
.....

     对应的的匹配方法就是:

 

def scrape_resource_url(html)
  %r{<p\s*align=[',"]?center[',"]?\s*>\s*<a\s*href=[',"](.*?)[',"]\s*>}mi =~ html
  $1
end

    返回的连接就是:'http://listen.putclub.com/resource/lessons/liurenxing/liurx/12.mp3'

                                                                                                                                                                

 

    当输入”1-12The One With the Dozen Lasagnas“时,得到”season-1“,还是用正则表达式

 

def extract_season_index(title)
  /(\d+)-/ =~ title
  "season-#{$1}"
end

 

                                                                                                                                                                     

 

 

    步骤4 ,建立mp3文件连接,将对白下载到对应的文件夹下,用之前得到的标题名来命名文件

     比如文件'http://listen.putclub.com/resource/lessons/liurenxing/liurx/12.mp3 '就下载到".../friends/season-1/1-12The One With the Dozen Lasagnas.mp3 "

 

     ps:在windows下,文件名不能包含"\/:*?"<>|"这些字符啊!

     下面是下载方法的实现:

 

def download(resource,root)
  url = URI.parse(resource[:url]) 
  unless FileTest.exist?(
 "D:\\friends\\#{extract_season_index(resource[:title].chomp)}\\#{resource[:title].chomp}.mp3")

Net::HTTP.start(url.host,url.port) do |http|
    start_time = Time.now
    puts "Start download #{resource[:title].chomp}.mp3"
    
data = http.get(url.path).body
    size = data.size
    if(size > 500)
    puts String(size) + "k"
    path = root + extract_season_index(resource[:title])
    FileUtils.makedirs(path) unless FileTest.exist?(path)
    File.open("D:\\friends\\#{extract_season_index(resource[:title].chomp)}\\#{resource[:title].chomp}.mp3",'wb') do |fin| 
        fin.write data
    end
    end_time = Time.now
    puts "Take #{end_time - start_time} seconds"
    else
      puts "Download fail"
      "download_fail"
    end
  end
  end
end

 

    ruby1.8.6的Net::HTTP中的get方法在连接较大的数据时,几乎都是连接超时 有人在rubyforge 上改写了ruby的rbuf_fill方法,原先的timeout参数太小,导致timeout的次数

    太多,所以会超时。ruby1.8.7和以后的版本修改了这个bug

 

    被改写的ruby方法在 \ruby\lib\ruby\1.8\net\protocol.rb 里

 

#def rbuf_fill
#  timeout(@read_timeout) {
#    @rbuf << @io.sysread(1024)
#  }
#end

def rbuf_fill
    begin
      @rbuf << @io.read_nonblock(4096)
    rescue Errno::EWOULDBLOCK
      if IO.select([@io], nil, nil, @read_timeout)
        @rbuf << @io.read_nonblock(4096)
      else
        raise Timeout::TimeoutError
      end
   end
end
 

    主要的步骤和方法都罗列出来啦,完整的ruby文件请下载附件,如果你懒得修改ruby源码的话,可以用附件中的

protocol.rb替换 \ruby\lib\ruby\1.8\net\ 下的protocol.rb. 完整的ruby脚本里还有下载记录的保存,避免了第二次运行脚本时再去连接已下载的mp3对白文件,不过与主题联系不大,我就不多说了。

 

下一篇是把当年明月的博客 ——《明朝那些事》的博文转为PDF导出,文章嘛还是下到PSP看来得爽嘛!

 

 

 

 

我们的目标就是——实用的代码!

 

 

 

 

 

 

 

 

  • 大小: 42.9 KB
  • 大小: 102 KB
4
1
分享到:
评论
2 楼 ruanqi 2009-02-17  
ruby还是挺简洁的
1 楼 天机老人 2009-02-08  
哈哈支持楼主,呵呵,ruby果然强。
这样看起来用java写也差不多是这么多代码量的样子!

相关推荐

Global site tag (gtag.js) - Google Analytics