有人知道Ruby Mechanize的缓存插件吗?

时间:2011-04-10 20:11:16

标签: ruby mechanize-ruby

我有一个基于Mechanize的Ruby脚本来抓取一个网站。我希望通过在本地缓存下载的HTML页面来加快速度,使整个“调整输出 - >运行 - >调整输出”循环更快。我不想只为这个脚本在机器上安装外部缓存。理想的解决方案是插入Mechanize并透明地缓存已获取的页面,图像等。

有人知道会有这样做的图书馆吗?或者另一种实现相同结果的方法(脚本第二次运行得更快)?

4 个答案:

答案 0 :(得分: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创建新版本的磁带,只需删除相应的文件。

答案 1 :(得分:2)

我不确定缓存页面会有多大帮助。更有帮助的是记录以前访问过的URL,这样您就不会重复访问它们。页面缓存没有实际意义,因为当您第一次看到页面时,您应该已经抓住了重要信息,所以您需要做的就是检查您是否已经看过它。如果有,请抓取您关心的摘要信息并根据需要进行操作。

我曾经使用Perl的Mechanize编写分析蜘蛛。 Ruby的Mechanize基于它。将先前访问过的URL存储在 SOME 类缓存中非常有用,就像哈希一样,但是,由于应用程序崩溃或主机在会话中断,所有以前的结果都将消失。在那时,一个真正的基于磁盘的数据库是必不可少的。

我喜欢Postgres,但即使SQLite也是不错的选择。无论您使用什么,都可以获得驱动器上的重要信息,以便在重启或崩溃时能够存活。

我推荐的其他内容是使用YAML文件来配置您的应用。将应用程序运行期间可能更改的每个参数放在那里。然后,编写应用程序,以便定期检查该文件的修改时间,并在发生更改时重新加载。这样,您可以动态调整其运行时行为。几年前,我不得不写一只蜘蛛来分析财富50强公司的多个网站。该应用程序运行了三周,与许多不同的网站绑定了该公司,因为我可以调整用于控制应用程序处理的页面的正则表达式,我可以在不关闭该应用程序的情况下对其进行微调。

答案 2 :(得分: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)

我在蜘蛛/刮刀中使用了这种技术,因此无需重新请求所有页面即可调整代码。 e.g:

# 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"]}

答案 3 :(得分:1)

如何将页面写入文件,将每个页面写入单个文件,以及分离调整和运行周期?