Posted filed under Ruby on Rails.

Photo by pnoeric

 いま、PhotoShareで使うために、高速なEvent Driven方式のネットワークライブラリ、EventMachineを調べています。

 このEventMachine、ほとんどの場合はサーバを作るときに使われていますが、HTTPクライアントの機能も実装されており、実はクローラの様な物を作るときにも利用することができます。

 今回はこっちを使いたかったのですが、ググってもほとんど情報が出てこなかったので、Seattle.rbで相談したところ、Aaronさん(RubyKaigi 2008でプレゼンしているのをustで見てコンタクトしました)からサンプルが貰えたので、それを元に、同時接続する様にしてみました。

 このコードだけだと役には立ちませんが、情報が少なかったので参考に上げておきます。

require 'rubygems'
require 'eventmachine'

CONCURRENCY = 2
TARGET_URL = 'http://localhost:3000/'

def create_connection
  puts ">>>> create"
  uri = URI.parse(TARGET_URL)
  request = Net::HTTP::Get.new(uri.request_uri)
  client = EventMachine::Protocols::HttpClient.send(:request,
                                                    :host        => uri.host,
                                                    :port        => uri.port,
                                                    :request_obj => request)
  client.callback do |result|
    $queue.delete client
    $queue << create_connection if $queue.size < CONCURRENCY

    puts ">>>> callback"
    p result
  end
  
  client.errback do
    # TODO
  end
  client
end

$queue = []
EventMachine.run do
  CONCURRENCY.times do
    $queue << create_connection
  end
end

3 Responses to “EventMachineを使ったクローラの書き方の足がかり”

  1. maimuzo

    自分もクローラーを使いたくて調べてた所だったのでとても参考になりました。
    これって、最大クライアント数(CONCURRENCY)までHTTPリクエストを並列実行する部分のソースですよね。
    こんなに簡単にできるんだ。
    TARGET_URLをキューから持ってくるようにして、resultのパースを自分で書けば(ここも便利なgemとかあるんだろうか)、比較的簡単にできそうな気がしてきました。
    skynetと絡ませたら面白そうですね。

  2. masuidrive

    そうですね。うちは別ポートでキューにURLを突っ込めるようにしたいなと思ってます。
    HTMLのパースなら、Hpricotあたりが有名だと思います。

    skynetってなんですか?

  3. maimuzo

    skynetはgoogleのMapReduceをrubyで実装したgemです。
    http://skynet.rubyforge.org/
    ただ、どうもコードをマップするのではなく、データをマップするようなので、あらかじめコードをワーカに配置しておかなければならないようですけどね。(よく理解してないんですけどね^^)
    EC2などで必要なときだけインスタンス立ち上げて、マップでクロール対象URLを蒔いて、結果を集計すれば個人でも計算可能量がものすごく増加すると思うので使ってみたいのですが、どういう風に使えばいいのかイマイチピンとこないのです。
    ググると日本語ではこれぐらいしか出てこないので困っています。 
    http://www.moongift.jp/2008/06/skynet/
    http://www.infoq.com/jp/news/2008/02/ruby-mapreduce-skynet
    GEM_HOMEの中のexampleが一番参考になりそうですが、読み解くのに時間がかかりそうです…