3

WebサイトをスクレイプするためのMechanizeベースのRubyスクリプトがあります。ダウンロードしたHTMLページをローカルにキャッシュして、「出力の微調整->実行->出力の微調整」サイクル全体を高速化することで、速度を上げたいと考えています。このスクリプトのためだけに、マシンに外部キャッシュをインストールする必要はありません。理想的なソリューションは、フェッチされたページや画像などを機械化して透過的にキャッシュするプラグインです。

これを行うライブラリを知っている人はいますか?または、同じ結果を達成する別の方法(スクリプトは2回目ではるかに高速に実行されます)?

4

4 に答える 4

8

この種のことを行う良い方法は、(素晴らしい)VCRジェムを使用することです。

これを行う方法の例を次に示します。

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にカセットの新しいバージョンを作成させる場合は、対応するファイルを削除するだけです。

于 2013-08-23T22:13:47.220 に答える
2

ページをキャッシュすることがそれほど役立つかどうかはわかりません。さらに役立つのは、以前にアクセスしたURLの記録を保持して、それらを繰り返し再アクセスしないようにすることです。ページを最初に見たときに重要な情報をすでに取得しているはずなので、ページのキャッシュは重要ではありません。必要なのは、すでにページを表示したかどうかを確認することだけです。持っている場合は、気になる要約情報を取得し、必要に応じて操作します。

私は以前、PerlのMechanizeを使用して分析スパイダーを作成していました。RubyのMechanizeはそれに基づいています。以前にアクセスしたURLをハッシュなどのキャッシュに保存する便利でしたが、アプリがクラッシュしたり、セッションの途中でホストがダウンしたりすると、以前の結果はすべて失われます。その時点では、実際のディスクベースのデータベースが不可欠でした。

私はPostgresが好きですが、SQLiteでさえ良い選択です。使用するものが何であれ、ドライブの再起動やクラッシュに耐えられる重要な情報を入手してください。

私がお勧めする他の何かは、アプリの構成にYAMLファイルを使用することです。アプリの実行中に変更される可能性のあるすべてのパラメーターをそこに配置します。次に、そのファイルの変更時刻を定期的にチェックし、変更があった場合は再読み込みするようにアプリを作成します。そうすれば、実行時の動作をその場で調整できます。数年前、フォーチュン50社の複数のWebサイトを分析するためにスパイダーを作成する必要がありました。このアプリは、その企業に関連するさまざまなサイトをスパイダーして3週間実行しました。アプリが処理するページを制御するために使用される正規表現を微調整できたため、アプリをシャットダウンせずに微調整できました。

于 2011-04-10T20:56:43.373 に答える
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)

私はスパイダー/スクレーパーでこの手法を使用して、すべてのページを再リクエストすることなくコードを微調整できるようにしました。例えば:

# 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"]}
于 2013-10-19T19:09:38.297 に答える
1

ページをファイルに書き込み、各ページを個別のファイルに書き込み、微調整と実行のサイクルを分離するのはどうですか?

于 2011-04-10T21:23:57.267 に答える