[Ruby] gems: Webクローラ anemone を使ってみる

ブログの調査を自動化できないかと思い、anemone を調べてみました。

公式サイトのサンプルをいろいろといじったり調べたりしたところ、ひとまず下記の2点を解決する必要がありそう。

  • クロールの対象ページが多くても、動作に支障がないようにしたい。
  • 指定した URL 以下にクロールを限定したい。

Contents

anemone と MongoDB をインストールする

anemone の標準では、メモリーにデータを保存するため、アクセス先のページが多いと支障が出てくるとのこと。
これを回避するためにストレージを利用するようで、定番は MongoDB のようなので、先人に習ってインストールを行います。

MongoDB のインストール

下記のとおり、インストールしました。

Gemfile

bundler で入れてみます。

% bundle init
Gemfile
# A sample Gemfile
source "https://rubygems.org"
gem "anemone", "~> 0.7.2"
gem "nokogiri", "~> 1.6.1"
gem "mongo", "~> 1.9.2"
gem "bson_ext", "~> 1.9.2"
% bundle

option

anemone のオプションを利用して、振る舞いを調整します。
オプションはこんなものがあるようです。

/lib/anemone/core.rb
    DEFAULT_OPTS = {
      # run 4 Tentacle threads to fetch pages
      :threads => 4,
      # disable verbose output
      :verbose => false,
      # don't throw away the page response body after scanning it for links
      :discard_page_bodies => false,
      # identify self as Anemone/VERSION
      :user_agent => "Anemone/#{Anemone::VERSION}",
      # no delay between requests
      :delay => 0,
      # don't obey the robots exclusion protocol
      :obey_robots_txt => false,
      # by default, don't limit the depth of the crawl
      :depth_limit => false,
      # number of times HTTP redirects will be followed
      :redirect_limit => 5,
      # storage engine defaults to Hash in +process_options+ if none specified
      :storage => nil,
      # Hash of cookie name => value to send with HTTP requests
      :cookies => nil,
      # accept cookies from the server and send them back?
      :accept_cookies => false,
      # skip any link with a query string? e.g. http://foo.com/?u=user
      :skip_query_strings => false,
      # proxy server hostname
      :proxy_host => nil,
      # proxy server port number
      :proxy_port => false,
      # HTTP read timeout in seconds
      :read_timeout => nil
    }

focus_crawl method

指定したURL以下をクロールさせるために、focus_crawl という method を使うようなサンプルを探して見ました。

ありがたいことにそのまま目的を果たせそうなので、利用してみます。

サンプル

まとめてみると、こんな形になりました。

anemone.rb
require 'rubygems'
require 'bundler/setup'
Bundler.require
options = {
  :user_agent => "AnemoneCrawler/0.0.1",
  :storage => Anemone::Storage.MongoDB,
  :delay => 1,
  :depth_limit => 1,
}
Anemone.crawl("http://www.example.com/", options) do |anemone|
  anemone.focus_crawl do |page|
    page.links.keep_if { |link|
      link.to_s.match(/test/)
    }
  end
  anemone.on_every_page do |page|
    if page.doc
      p page.url.to_s
      p page.doc.at('title').inner_html
    end
  end
end

実行結果

% ruby anemone.rb
"http://www.example.com/"
"Example Domain"

MongoDB の内容を確認する

ストレージとして利用した MongoDB にどんなデータが入ったのか確認してみます。

% mongo
MongoDB shell version: 2.4.9
connecting to: test
> show dbs;
anemone 0.203125GB
local   0.078125GB
> use anemone;
switched to db anemone
> show collections;
pages
system.indexes
> db.pages.find();
{ "_id" : ObjectId("52d54b1b4ced2ab4af3c12dd"), "url" : "http://www.example./", "headers" : BinData(0,"BAh7BkkiEWNvbnRlbnQtdHlwZQY6BkVUWwZJIgAGOwBU"), "data" : BinData(0,"BAhVOg9PcGVuU3RydWN0ewA="), "body" : null, "links" : [ ], "code" : null, "visited" : null, "depth" : 0, "referer" : "", "redirect_to" : "", "response_time" : null, "fetched" : false }

補遺

取得したデータの Parse は Nokogiri が担当している。

著作権。