クローラー
同様のものを以前につくったが遅すぎて(30分とか)常用できなかった。ファイル保存の機能もなかった。今回のものは速度が50倍ぐらいにはなったのではなかろうか。
#! /usr/bin/env ruby #-*-coding:utf-8-*- require 'term/ansicolor' class String include Term::ANSIColor end class MyJobAnisoku def initialize(args = { }) require 'rubygems' require 'kconv' require 'mechanize' require 'net/http' @a = args @a[:url] ||= 'http://youtubeanisoku1.blog106.fc2.com/' @a[:url] = URI.parse @a[:url] unless @a[:url].class == URI::HTTP @agent = Mechanize.new @a[:status] ||= :new raise "job have no machine error" unless @a[:machine] end #最初のとっかかり更新状況を取ってきて個別の紹介ページのjobにする def tokkakari print "NEW" @agent.get @a[:url] links_kousins = @agent.page.links_with(:text => /#{"更新状況".toutf8}/) targs = [] links_kousins.each do |link| targs << link.uri end targs.each_with_index do |link,i| break if i > 6 job = MyJobAnisoku.new( :url => link, :status => :second, :machine => @a[:machine] ) @a[:machine].retry job end end #更新情報のページにアクセスして個別の紹介ページのjobにする def second print "phase2".yellow @agent.get @a[:url] links_kousin = @agent.page/"/html/body/table/tr[2]/td/table/tr/td[2]/div[4]/ul/li/a/@href" # links_kobetuには個別のページが入っている links_kobetu = [] links_kousin.each do |link| links_kobetu << $1 if link.value =~ /(http:\/\/youtubeanisoku.*)/ end #links_kobetuのについてそれぞれjobをつくって突っ込む links_kobetu.each do |link| job = MyJobAnisoku.new( :url => link, :status => :kobetu, :machine => @a[:machine] ) @a[:machine].retry job end end #say-moveにアクセスしてvideourlを取得してvideoのjobにする def third print "say-move".green #smにはtitleとurlが入っている sm = { :title => @a[:title],:url => @a[:url]} @agent.get(sm[:url]) set = @agent.page/"/html/body/div/div[2]/div[7]/div[2]/input/@value" if set[0] sm[:videourl] = set[0].value end job = MyJobAnisoku.new( :url => sm[:videourl], :title => sm[:title], :status => :video, :machine => @a[:machine] ) @a[:machine].retry job end #個別のページにアクセスしてsay-moveのjobにする def kobetu print "phase3".yellow @agent.get @a[:url] nodeset = @agent.page/"/html/body/table/tr[2]/td/table/tr/td[2]/div[4]/div[2]" begin titles = nodeset[0].inner_text. gsub(' ',''). gsub(' ',''). gsub('「Daum」|',''). gsub('【Yahoo!】',''). gsub('veoh',''). gsub('SM|',''). gsub('|',''). split("\r\n"). select{|e| $1 if e=~/(第.*)/ }. map{|k| k =~ /(第(\d{1,2}).*)/; { :episode => $2, :title => $1} } titles.reverse! _tt = @agent.page.title.gsub(' ★ You Tube アニ速 ★','') #取得件数調整ハードコーディング title = _tt + titles.shift[:title].to_s title2 = _tt + titles.shift[:title].to_s title3 = _tt + titles.shift[:title].to_s title4 = _tt + titles.shift[:title].to_s title5 = _tt + titles.shift[:title].to_s rescue => ex p ex return end nodeset_vs = @agent.page/"/html/body/table/tr[2]/td/table/tr/td[2]/div[4]/div[2]/a/@href" _dd = [] nodeset_vs.each do |va| _dd << $1 if va.value =~ /(http:\/\/say-move\.org\/comeplay\.php.*)/ end _dd.reverse! #取得件数調整ハードコーディング url = _dd.shift url2 = _dd.shift url3 = _dd.shift url4 = _dd.shift url5 = _dd.shift #取得件数調整ハードコーディング unless url.nil? job = MyJobAnisoku.new( :url => url, :title => title, :status => :third, :machine => @a[:machine] ) @a[:machine].retry job end unless url2.nil? job = MyJobAnisoku.new( :url => url2, :title => title2, :status => :third, :machine => @a[:machine] ) @a[:machine].retry job end unless url3.nil? job = MyJobAnisoku.new( :url => url3, :title => title3, :status => :third, :machine => @a[:machine] ) @a[:machine].retry job end unless url4.nil? job = MyJobAnisoku.new( :url => url4, :title => title4, :status => :third, :machine => @a[:machine] ) @a[:machine].retry job end unless url5.nil? job = MyJobAnisoku.new( :url => url5, :title => title5, :status => :third, :machine => @a[:machine] ) @a[:machine].retry job end end #videoを取得して保存する def video savedir = @a[:machine].savedir Dir.chdir savedir filename = "#{@a[:title]}.mp4" savepath = "#{savedir}/#{filename}" puts "Fetching".green.bold + savepath if File.exist?(savepath) && File.size(savepath) > 1024 * 1024 * 3 puts "File Already Saved".yellow.bold return end #省メモッリ command = "curl -# -L -R -o '#{filename}' '#{@a[:url].host}#{@a[:url].path}'" system command =begin メモリ食い過ぎ。2G超とかwwww begin @http = EventMachine::Protocols::HttpClient.request( :host => @a[:url].host, :port => @a[:url].port, :request => @a[:url].path ) rescue => ex p ex return end @http.callback {|response| if response[:status] == 200 puts "#200".green open(savepath,"wb") do |io| io.write response[:content] end elsif response[:status] == 302 puts "302".red.bold location = "" response[:headers].each do |elem| p elem location = $1 if elem =~ /Location:\s(.*)/ end job = MyJobAnisoku.new( :url => location, :title => @a[:title], :status => :video, :machine => @a[:machine] ) @a[:machine].retry job else puts response[:status].to_s.red.bold puts response[:headers].to_s.red.bold # raise "HTTP Status Error" end } =end end def run #スレッドをつくってMechanizeを並行実行 t = Thread.new do case @a[:status] when :new then tokkakari when :second then second when :kobetu then kobetu when :third then third when :video then video end end end end # machine module MyMachine attr_accessor :queue def initialize require 'thread' @queue = Queue.new end def setup setupjobs setupmachine end def go puts "You need write the go method!" end def retry(job) @queue.push job end private def setupjobs puts "You need write the setupjobs method!" end def setupmachine puts "You need write the setupmachine method!" end end # for This Work class MyMachineAnisoku include MyMachine attr_accessor :savedir def initialize(args={ }) super() args[:savedir] ||= "/Users/seijiro/Desktop/video" @savedir = args[:savedir] begin Dir::mkdir(@savedir, 0777) rescue => ex warn ex end require 'rubygems' require 'eventmachine' # @gaman is weight for controll EventMachine finish @gaman = 0 end def go EM.run do EM.add_periodic_timer(0) do EM.stop if should_stop_machine? @queue.pop.run unless @queue.empty? end end puts "End of fetch".green.bold end private # EventMachine用に再定義 def setupjobs ajob = MyJobAnisoku.new( :machine => self ) @queue.push ajob end # Machineは終了すべきか? def should_stop_machine? @gaman += 1 if @queue.empty? print "gaman:#{@gaman}/job:#{@queue.size}" return @queue.empty? && @gaman > 500 end end #################################################### machine = MyMachineAnisoku.new(:savedir => "/Users/seijiro/Desktop/video") #<=modify! machine.setup machine.go __END__ これは何: ここ数週間の動画を取得するスクリプトです 使い方: 1.スクリプトを保存してchmod +x 2.savedir:を変更 2.スクリプト実行 コメント: XPathつかってみた。 Firebugで右クリック=>Xpathをコピー=>Emacsに貼りつけとかいままでなんでやってこなかったのかと。瞬殺ですね。 cronで毎朝6時とかににキックしとけば良いと思います。 かなりな速度でvideoのurlに到達できます。スレッドの効果です。 100M超えないのでメモリに優しいです。EMの効果です。 50%超えないのでCPUにもやさしいです。EMの効果です。 queueの件数が最大500に満たないので特にコネクション制限とかは掛けません。 Socket数/Fileハンドル数超過とかは起きないと思います。