如何使用OpenURI和Nokogiri快速有效地打开和解析大量网页



我正在用Ruby编写一个应用程序,它可以从一个拥有10000多个页面的网站上搜索和获取数据。我使用OpenURI和Nokogiri打开和解析网页,从中获取数据,并将其保存到本地数据文件::

#An example
page = Nokogiri::HTML(open("http://example.com/books/title001.html"))    
#Get title, author, synopsys, etc from that page 

对于拥有ADSL连接的我来说,打开一个页面平均需要1秒。因为该网站大约有10000个页面,打开所有页面并获取所有书籍的数据需要3个多小时,这对于这个应用程序来说是不可接受的时间,因为我的用户不想等待那么长时间。

如何使用OpenURI和Nokogiri快速有效地打开和解析大量网页?

如果我不能对他们那样做,我该怎么办?一些做同样工作的应用程序(列出书籍,从页面中获取所有数据并保存到文件中),比如一些漫画下载程序,如何在大型漫画网站(约10000本)上只需要5-10分钟就可以做到这一点?

不要先使用OpenURI;如果你使用九头蛇和伤寒,有一个更好的方法。

就像拥有100个蛇头的神话野兽的现代代码版本一样,Typhoeus并行运行HTTP请求,同时干净地封装处理逻辑。

并行请求:

hydra = Typhoeus::Hydra.new
10.times.map{ hydra.queue(Typhoeus::Request.new("www.example.com", followlocation: true)) }
hydra.run

在文档的后面。。。

如何在执行队列后返回一组响应:

hydra = Typhoeus::Hydra.new
requests = 10.times.map { 
  request = Typhoeus::Request.new("www.example.com", followlocation: true)
  hydra.queue(request) 
  request
}
hydra.run
responses = request.map { |request|
  request.response.response_body
}

request.response.response_body是您想要用Nokogiri的解析器包装的行:

Nokogiri::HTML(request.response.response_body)

在这一点上,您将有一系列DOM要遍历和处理。

但是等一下!还有更多!

因为您想节省一些处理时间,所以您需要设置一个线程和队列,推送解析后的DOM(或仅推送未解析的HTML response_body),然后让线程处理并写入文件。

这并不难,但随着它成为一本小书,Stack Overflow开始将这个问题排除在范围之外。阅读线程和队列文档,尤其是关于生产者和消费者的部分,您应该能够将其拼凑在一起。这来自ri Queue文档:

= Queue < Object
(from ruby core)
------------------------------------------------------------------------------
This class provides a way to synchronize communication between threads.
Example:
  require 'thread'
  queue = Queue.new
  producer = Thread.new do
    5.times do |i|
       sleep rand(i) # simulate expense
       queue << i
       puts "#{i} produced"
    end
  end
  consumer = Thread.new do
    5.times do |i|
       value = queue.pop
       sleep rand(i/2) # simulate expense
       puts "consumed #{value}"
    end
  end
------------------------------------------------------------------------------
= Class methods:
  new
= Instance methods:
  <<, clear, deq, empty?, enq, length, num_waiting, pop, push, shift, size

我用它来并行处理大量的URL,而且它很容易设置和使用。使用Threads可以做到这一点,而不使用Typhoeus,但我认为利用现有的、写得很好的工具比尝试推出自己的工具更明智。

一些做同样工作的应用程序(列出书籍,从页面中获取所有数据并保存到文件中),比如一些漫画下载程序,如何在大型漫画网站(约10000本)上只需要5-10分钟就可以做到这一点?

他们有:

  • 快速连接到互联网
  • CPU处理多个连接的能力
  • RAM可以运行多个线程并保存大量等待处理的页面

处理这么多页面并不难,你只需要现实地对待你的资源,并明智地使用可用的资源。

我的建议是什么?

  • 不要试图一次打开100页;你的连接和CPU会堵塞,你的吞吐量会降低,而且你的应用程序可能会缺少RAM
  • 运行测试来确定回报递减点在哪里,并且一次不允许超过这个数量的请求
  • 消费线程将很容易领先于生产线程,因此您只需要一个消费者

相对而言,在执行http请求时会有很多等待,这对于多个线程/进程来说是一个很好的用例。您可以创建一个工作线程/进程池,从一个队列中检索请求数据,然后将结果放入另一个队列,主线程可以从中读取。

请参见此处:https://blog.engineyard.com/2014/ruby-thread-pool

一些做同样工作的应用程序如何工作(列出书籍,获取全部页面中的数据并保存到文件中),例如一些漫画下载程序对于大型漫画网站(约10000个标题)?

计算能力。如果你有一台10000核心的计算机(或者10000台每个有一个核心的计算机),你可以为每个请求启动一个进程,然后所有请求都会同时执行。完成所有请求的总时间将是完成最长请求所需的时间,而不是所有请求的所有时间之和。

相关内容

  • 没有找到相关文章

最新更新