不要先使用 OpenURI;如果你使用Hydra and Typhoeus,有一个更好的方法。
就像具有 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 变成一本小书,这个问题开始超出了 Stack Overflow 的范围。阅读Thread 和Queue 文档,尤其是关于生产者和消费者的部分,您应该能够将它们拼凑起来。这是来自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 个标题)?
他们有:
- 快速连接到互联网。
- 处理多个连接的 CPU 能力。
- RAM 用于运行多个线程并持有大量等待处理的页面。
处理这么多页面并不难,您只需要对自己的资源持现实态度并明智地使用可用的资源。
我有什么建议?
- 不要试图一次打开 100 个页面;您的连接和 CPU 将被阻塞,您将降低吞吐量,而且您可能会耗尽您的应用程序的 RAM。
- 运行测试以确定您的收益递减点在哪里,并且一次不允许超过该数量的请求。
- 消费线程将轻松领先于生产线程,因此您只需要一个消费者。