Ruby中用于em-synchrony的嵌套迭代器

时间:2012-06-12 15:39:17

标签: ruby parsing eventmachine

我正在尝试使用eventmachine和em-synchrony编写解析器(解析邮政编码的街道和房屋)。问题是我要解析的网站有嵌套结构 - 对于每个邮政编码,有很多街道页面,其中有分页。所以算法非常简单:

  • 为每个邮政编码
    • 访问postcal代码索引页面
      • 解析索引页
      • 解析分页
      • 为每个分页页面解析此页面

以下是此类解析器的一个示例(可行):

require "nokogiri"
require "em-synchrony"
require "em-synchrony/em-http"

def url page = nil
  url = "http://gistflow.com/all"
  url << "?page=#{page}" if page
  url
end

EM.synchrony do
  concurrency = 2

  # here [1] is array of index pages, for this template let it be just [1]
  results = EM::Synchrony::Iterator.new([1], concurrency).map do |index, iter|
    index_page = EM::HttpRequest.new(url).aget

    index_page.callback do
      # here we make some parsing and find out wheter index page 
      # has pagination. The worst case is that it has pagination
      pages = [2,3,4,5]

      unless pages.empty?
        # here we need to parse all pages
        # with urls like url(page)
        # how can I do it more efficiently?
      end

      iter.return "SUCC #{index}"
    end

    index_page.errback do 
      iter.return "ERR #{index}"
    end
  end

  p results
  EM.stop
end

所以诀窍在这个区块内:

unless pages.empty?
  # here we need to parse all pages
  # with urls like url(page)
  # how can I do it more efficiently?
end

如何在synchrony迭代器循环中实现嵌套的EM HTTP调用?

我尝试了不同的方法,但每次遇到“无法从根光纤中屈服”或者调用errback块时出现错误。

1 个答案:

答案 0 :(得分:2)

一种解决方案是使用FiberIterator和同步.get代替.aget

require "em-synchrony"
require "em-synchrony/em-http"
require "em-synchrony/fiber_iterator"

def url page = nil
  url = "http://gistflow.com/all"
  url << "?page=#{page}" if page
  url
end

EM.synchrony do
  concurrency = 2

  master_pages = [1,2,3,4]

  EM::Synchrony::FiberIterator.new(master_pages, concurrency).each do |iter|
    result = EM::HttpRequest.new(url).get
    if result
      puts "SUCC #{iter}"
      detail_pages = [1,2,3,4]       
      EM::Synchrony::FiberIterator.new(detail_pages, concurrency).each do |iter2|
        result2 = EM::HttpRequest.new(url).get
        puts "SUCC/ERR #{iter} > #{iter2}"
      end
    else
      puts "ERR #{iter}"
    end
  end

  EM.stop

end