2011-04-10 48 views
3

我有一個基於Mechanize的Ruby腳本來抓取一個網站。我希望通過在本地緩存下載的HTML頁面來加速它,以使整個「調整輸出 - >運行 - >調整輸出」循環更快。我寧願不必爲此腳本在機器上安裝外部緩存。理想的解決方案將插件機械化並透明地緩存提取的頁面,圖像等。任何人都知道Ruby Mechanize的緩存插件?

任何人都知道圖書館會這樣做嗎?或者達到相同結果的另一種方式(腳本第二次運行更快)?

+0

我不知道這是否會爲你想出來的工作是什麼因爲它顯然是爲反向代理而不是代理設計的,但它可能會重新用於執行你所需要的功能? http://rtomayko.github.com/rack-cache/ – 2011-04-10 20:41:19

回答

1

如何將頁面寫入文件,每個頁面放在單個文件中,然後分離調整和運行週期?

+0

您仍然可能會遇到許多重複的頁面,而無法解析多個重定向到同一頁面。 – 2011-04-10 22:01:01

+0

單獨的讀取和掃描腳本是一個好主意,並且不難實現。謝謝。 – 2011-04-11 04:36:09

2

我不確定緩存頁面會有多大幫助。更有幫助的是有一個以前訪問的URL的記錄,所以你不會重複訪問它們。頁面緩存是沒有意義的,因爲當您第一次看到該頁面時,您應該已經獲取了重要信息,因此您只需檢查是否已經看到該頁面即可。如果有,請獲取您關心的摘要信息並根據需要對其進行處理。

我以前用Perl的Mechanize寫分析蜘蛛。 Ruby的機械化是基於它的。將以前訪問過的URL存儲在中有些緩存很有用,就像散列一樣,但是,由於應用程序崩潰或主機在會話期間停止運行,所有以前的結果都將消失。在這一點上,真正的基於磁盤的數據庫至關重要。

我喜歡Postgres,但即使是SQLite也是不錯的選擇。無論您使用何種方式,都可以在驅動器重新啓動或崩潰後獲取重要信息。

我推薦的其他東西是使用YAML文件來配置您的應用程序。將每個可能在應用程序運行期間更改的參數都放在那裏。然後,編寫應用程序,以便定期檢查該文件的修改時間,並在出現更改時重新加載該文件。這樣,您可以即時調整其運行時行爲。幾年前,我不得不寫一篇蜘蛛來分析財富50強公司的多個網站。該應用運行了三週,其中有許多不同的網站與該公司綁定,並且因爲我可以調整用於控制應用處理哪些頁面的正則表達式,所以我可以在不關閉該應用的情況下對其進行微調。

+0

謝謝。在運行過程中,我確實保留了訪問頁面的散列,以避免陷入循環。我還可以從Mechanize的來源看到,它還保留了歷史記錄,並在可以的時候使用If-Modified-Since。我希望有人可能延長了這一點,把歷史放在磁盤或數據庫中或其他任何東西上。 – 2011-04-11 04:32:54

8

做這種事情的一個好方法是使用(AWESOME)VCR gem

這裏,你會怎麼做一個例子:

require 'vcr' 
require 'mechanize' 

# Setup VCR's configs. The cassette library directory is where 
# all of your "recordings" are saved as YAML files. 
VCR.configure do |c| 
    c.cassette_library_dir = 'vcr_cassettes' 
    c.hook_into :webmock 
end 

# Make a request... 
# The first time you do this it will actually make the call out 
# Subsequent calls will read the cassette file instead of hitting the network 
VCR.use_cassette('google_homepage') do 
    a = Mechanize.new 
    a.get('http://google.com/') 
end 

正如你可以看到... ... VCR記錄通信的第一次運行一個YAML文件:

mario$ find tester -mindepth 1 -maxdepth 3 
tester/vcr_cassettes 
tester/vcr_cassettes/google_homepage.yml 

如果您想要VCR創建磁帶盒的新版本,只需刪除相應的文件即可。

2

如果您在第一次請求後存儲了有關該頁面的一些信息,則可以稍後重新生成該頁面,而無需從服務器重新請求該頁面。

# 1) store the page information 
# uri: a URI instance 
# response: a hash of response headers 
# body: a string 
# code: the HTTP response code 
page = agent.get(url) 
uri, response, body, code = [page.uri, page.response, page.body, page.code] 

# 2) rebuild the page, given the stored information 
page = Mechanize::Page.new(uri, response, body, code, agent) 

我在spiders/scrapers中使用了這種技術,這樣就可以調整代碼而無需重新請求所有頁面。例如:

# agent: a Mechanize instance 
# storage: must respond to [] and []=, and must accept and return arbitrary ruby objects. 
# for in-memory storage, you could use a Hash. 
# or, you could write something that is backed by a filesystem, mongodb, riak, redis, s3, etc... 
# logger: a Logger instance 
class Foobar < Struct.new(:agent, :storage, :logger) 

    def get_cached(uri) 
    cache_key = "_cache/#{uri}" 

    if args = storage[cache_key] 
     logger.debug("getting (cached) #{uri}") 
     uri, response, body, code = args 
     page = Mechanize::Page.new(uri, response, body, code, agent) 
     agent.send(:add_to_history, page) 
     page 

    else 
     logger.debug("getting (UNCACHED) #{uri}") 
     page = agent.get(uri) 
     storage[cache_key] = [page.uri, page.response, page.body, page.code] 
     page 

    end 
    end 

end 

,你可以使用這樣的:

require 'logger' 
require 'pp' 
require 'rubygems' 
require 'mechanize' 

storage = {} 

foo = Foobar.new(Mechanize.new, storage, Logger.new(STDOUT)) 
foo.get_cached("http://ifconfig.me/ua") 
foo.get_cached("http://ifconfig.me/ua") 
foo.get_cached("http://ifconfig.me/ua") 
foo.get_cached("http://ifconfig.me/encoding") 
foo.get_cached("http://ifconfig.me/encoding") 

pp storage 

打印出以下信息:

D, [2013-10-19T14:13:32.019291 #18107] DEBUG -- : getting (UNCACHED) http://ifconfig.me/ua 
D, [2013-10-19T14:13:36.375649 #18107] DEBUG -- : getting (cached) http://ifconfig.me/ua 
D, [2013-10-19T14:13:36.376822 #18107] DEBUG -- : getting (cached) http://ifconfig.me/ua 
D, [2013-10-19T14:13:36.376910 #18107] DEBUG -- : getting (UNCACHED) http://ifconfig.me/encoding 
D, [2013-10-19T14:13:52.830416 #18107] DEBUG -- : getting (cached) http://ifconfig.me/encoding 
{"_cache/http://ifconfig.me/ua"=> 
    [#<URI::HTTP:0x007fe4ac94d098 URL:http://ifconfig.me/ua>, 
    {"date"=>"Sat, 19 Oct 2013 19:13:33 GMT", 
    "server"=>"Apache", 
    "vary"=>"Accept-Encoding", 
    "content-encoding"=>"gzip", 
    "content-length"=>"87", 
    "connection"=>"close", 
    "content-type"=>"text/plain"}, 
    "Mechanize/2.7.2 Ruby/2.0.0p247 (http://github.com/sparklemotion/mechanize/)\n", 
    "200"], 
"_cache/http://ifconfig.me/encoding"=> 
    [#<URI::HTTP:0x007fe4ac99d2a0 URL:http://ifconfig.me/encoding>, 
    {"date"=>"Sat, 19 Oct 2013 19:13:48 GMT", 
    "server"=>"Apache", 
    "vary"=>"Accept-Encoding", 
    "content-encoding"=>"gzip", 
    "content-length"=>"42", 
    "connection"=>"close", 
    "content-type"=>"text/plain"}, 
    "gzip,deflate,identity\n", 
    "200"]} 
相關問題