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

Ruby 如何使用OpenURI和Nokogiri快速有效地打开和解析大量网页?,ruby,parsing,web-crawler,nokogiri,open-uri,Ruby,Parsing,Web Crawler,Nokogiri,Open Uri,我正在用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连接的人来说,打开一个页面

我正在用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分钟就可以完成这项工作呢?

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

请看这里:

一些做同样工作的应用程序(列出书籍,获取全部)如何工作 来自页面的数据并保存到文件中),例如一些漫画下载程序 对于大型漫画网站(大约10000个),只需5-10分钟即可完成 头衔)


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

不要先使用OpenURI;有一个更好的方法,如果你使用

就像现代代码版本的100个蛇头的神话野兽一样,Typhous并行运行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
request.response.response\u body
是要用Nokogiri的解析器包装的行:

Nokogiri::HTML(request.response.response_body)
在这一点上,您将有一系列DOM需要遍历和处理

但是等等!还有更多

因为您想要节省一些处理时间,所以您需要设置一个线程和队列,推送解析的DOM(或者只推送未解析的HTML
response\u body
),然后进行线程处理并写入文件

这并不难,但当它成为一本小书时,它开始将问题排除在堆栈溢出的范围之外。阅读本手册和文档,特别是关于生产者和消费者的部分,您应该能够将其拼凑起来。这来自
ri队列
文档:

= 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
=队列<对象
(来自ruby core)
------------------------------------------------------------------------------
此类提供了一种同步线程之间通信的方法。
例子:
需要“线程”
queue=queue.new
producer=Thread.new do
5.3倍于我|
睡眠兰德(i)#模拟费用

谢谢,我会试试你的解决方案。关于计算能力,我不认为manga downloader软件是这样的,因为即使在低规格、高速连接的计算机中,打开和获取数据也不需要很长时间,只需要30-45分钟。顺便说一句,它们大多是用编译语言编写的,这有关系吗?我认为你的计算机的处理能力与漫画无关——重要的是漫画的计算能力。我不知道漫画是什么,但如果你向漫画发送一个请求,上面写着“给我所有这些网页。”然后漫画发送请求,然后将结果汇总并发送到你的计算机,则是漫画的计算能力决定了所有请求完成的速度(漫画只是日本漫画书的一个词,不是硬件,我用的是“漫画下载器”因为这些软件的名字叫so..如果你不高兴的话,很抱歉。好吧,漫画是你下载的一些软件--那么这与你的计算机的处理能力有关。如果你有一台单核计算机,而且下载速度很快,那么我想软件一定是在使用线程。
= 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