一個事件驅動的圖片爬蟲

起因

  1. 無聊的時候會翻出去看看國外的漫畫,然而一頁一頁加載總是會很慢,偶爾還需要多刷新幾次才能顯示出來,非常影響體驗。于是就寫了個腳本去抓某一個漫畫下所有的圖片,這樣跑一遍腳本,就能在本地看圖片了。

  2. 為了偷懶,第一個版本用的單線程模型,幾百張圖片串行請求,真的慢。

  3. 實際工作中一直沒什么機會用到異步IO,正好拿來練練手。

分析

并發的下載圖片,有多線程和事件驅動兩套方案。

多線程的實現方式,例如一部漫畫有300張圖,我不可能開300個Thread,系統受不了。比較實際的做法是使用一個容量為N的ThreadPool,那么,同時就只能發出N個請求,然后所有線程Block等待,其實效率也不高

然而事件驅動的方式就不一樣了,我可以一口氣把所有請求發出去,當有請求完成時,就調用事先定義的回調Handle,實現了300張圖片的并行下載。

先上圖看看效果

從圖中就可以看出,所有的請求都發出去之后,才陸續有響應結果亂序到達。這就是典型的異步IO的情景。

基于EventMachine的異步圖片爬蟲

EventMachine是ruby社區知名的事件驅動庫,類似于Netty、NodeJS

通過 EM.run{}就可以開始一個事件循環

以下是關鍵代碼

  #img_info = [{file_name: '1.jpg', url:'xxx'}...]

  def getImg(img_info)
    EM.run{ #開啟事件循環
      multi = EventMachine::MultiRequest.new #request容器
      @img_info_copy = img_info.dup
      img_info.each do |info|
        file_name = File.join(@dir, info[:file_name])
        if FileTest::exist?(file_name)
          @img_info_copy.delete(info)
          puts "#{file_name} skip".blue
          next
        end
        puts "#{file_name} start".green
        req = EventMachine::HttpRequest.new(info[:url]).get #創建request
        multi.add "#{file_name}",req
        req.callback { #成功回調
          File.open(file_name, 'w') { |file| file.write(req.response) }
          @img_info_copy.delete(info)
          puts "#{file_name} done".green
        }
        req.errback { #失敗回調
          puts "#{file_name} fail".red
        }
      end
      multi.callback do #所有request都完成后的回調
        if @img_info_copy.size == 0 #如果沒有圖片下載失敗
          EM.stop
        else #遞歸調用,重新下載的圖片
          puts "Total fails: #{@img_info_copy.size}, solving...".red
          getImg @img_info_copy.dup
        end
      end
    }
  end

遇到的小坑

EM.run {}之后,主線程就block了,所有寫在它后面的代碼都不執行

效果

通過這次的優化,下載一部兩三百頁漫畫的時間從之前單線程版本的二十多分鐘,變成了現在的兩分鐘左右!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,287評論 25 708
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 原文地址 http://www.cnblogs.com/kenshincui/p/3983982.html 大家都...
    怎樣m閱讀 1,302評論 0 1
  • 這兩天正值清明節小長假,相信有很多人仍然以傳統的方式甚至是迷信的方式去懷念那些故去的先人。我之前亦是如此,每到清明...
    錦時2016閱讀 350評論 0 0
  • 牙齒 ,是我們每一個人都擁有的器官,它們對于我們每天的生活來說真可謂不可或缺,我們用它們來咀嚼食物,我用依靠它們來...
    TealunDu閱讀 284評論 0 0