我有一个基于Mechanize的Ruby脚本来抓取一个网站。我希望通过在本地缓存下载的HTML页面来加快速度,使整个“调整输出 - >运行 - >调整输出”循环更快。我不想只为这个脚本在机器上安装外部缓存。理想的解决方案是插入Mechanize并透明地缓存已获取的页面,图像等。
有人知道会有这样做的图书馆吗?或者另一种实现相同结果的方法(脚本第二次运行得更快)?
答案 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)
如何将页面写入文件,将每个页面写入单个文件,以及分离调整和运行周期?