Rubyでスクレイピングしてみました。


スクレイピングに挑戦したのでサンプルコードを公開。
スクレイピング楽しいね

Railsではなく素のRubyコードを書きました。
gemはbundlerでインストール。
bundlerでインストールしたgemを読み込む方法はこちら

mechanize編

最初に挑戦したのはmechanizeというgem。
WEBサイトのインタラクションを自動化してくれるgemだそうです。
http://docs.seattlerb.org/mechanize/

今回は、絵本ナビから、
「くすのきだんち」シリーズのタイトル一覧と表紙画像を取得して、
タイトルをターミナルに表示、画像をローカルに保存します。

では早速作業開始。

$ mkdir scraping
$ cd scraping
$ rbenv local 2.2.3
$ bundle init
$ vim Gemfile
// gem 'mechanize'と追記してください。

$ bundle install --path vendor/bundle
$ touch ehon.rb
ehon.rb
# bundler経由でインストールしたgemを有効にするには下記のようにする
require 'bundler'
Bundler.require

# 検索したい絵本のタイトル URL用に日本語をエンコーディングする必要あり
keyword = "くすのきだんち".encode("Shift_JIS")

# 「K」というパラメーターにkeywordを渡してやれば検索結果の一覧を表示できるみたい
target_url = "http://www.ehonnavi.net/ehon01.asp?sel=1&K=#{keyword}"

# 画像の格納ディレクトリ なければ作る
dir_path = "./imgs"
FileUtils.mkdir_p(dir_path) unless FileTest.exist?(dir_path)

# スクレイピング用のコード
# クラス名'.detailOneCol'で絞り込んで、eachでまわしながら、
# 1件ずつタイトルを出力 画像は保存
agent = Mechanize.new
search_page = agent.get(target_url)
search_page.search('.detailOneCol').each do |item|
 puts title = item.search('div.text h3').inner_text # さらに絞り込み
 search_page.image_with(alt: "#{title}").fetch.save("#{dir_path}/#{title}.jpg") # altの値がtitleと一致しているので絞り込める
end

できたら、

$ ruby ehon.rb

わお!すごい
たったこれだけで望みが叶いました。

scraping.rb
agent = Mechanize.new
search_page = agent.get('http://example.com')
p search_page.links[0].click

とすると、リンク先のページも取得できます。

scraping.rb
agent = Mechanize.new
search_page = agent.get('http://example.com')
form = search_page.forms[0]
form.name = 'name'
form.password = 'secret'
p agent.submit(form)

とすると、フォームの項目を入力してサブミットした先のページを取得できます。

しかし、mechanizeは普通に使うと、JavaScriptを実行できません。
あれっ、どうしよう

Capybara + Poltergeist(PhantomJS)編

クリックイベントなどJSを実行して動的にページを操作したい場合は、
ブラウザ上のアクションをシュミレートするCapybaraと、
JavaScriptのドライバを組み合わせて実現します。

今回はドライバにPhantomJSを使用します。
さらにRubyからPhantomJSを扱えるように、Poltergeistというgemを導入します。

Capybara
https://github.com/jnicklas/capybara

Poltergeist
https://github.com/teampoltergeist/poltergeist

Gemfileに追記。

gem 'capybara'
gem 'poltergeist'

できたら、bundle install

PhantomJSもインストールしてください。

$ brew install phantomjs

バンダイチャンネルから、「犬夜叉 第1期」全44話の各話タイトルをターミナルに表示してみます。

http://www.b-ch.com/ttl/index.php?ttl_c=2277
にアクセスすると、ページの右側に「作品情報」が見えると思います。
下部のメニューから「各話あらすじ」のリンクをクリックすると、onClickイベントで第1話のタイトルとあらすじが表示されます。
「各話あらすじ」という見出しの下のページネーションをクリックしていくと、さらにonClickイベントで内容が書き換えられて、各話のタイトルとあらすじが確認できます。

これをCapybaraを使って、自動化すると下記のようになります。

$ touch bandai.rb
bandai.rb
require 'bundler/setup'
require 'capybara/poltergeist'
Bundler.require

Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, {:js_errors => false, :timeout => 1000 })
end
session = Capybara::Session.new(:poltergeist)
session.visit "http://www.b-ch.com/ttl/index.php?ttl_c=2277"
puts session.status_code
puts '各話タイトル'

# 「各話あらすじ」をクリックする => onClickが実行される 
session.find('div.ttlinfo-menu').all('ul')[0].all('li')[2].find('a').click

# 第1話タイトル
puts session.find('div#ttlinfo-stry').find('dt').text

# 第2話タイトル〜
# 最終話は動的に取得してもよいかも
2.upto(44) do |num|
  # onClickイベント ページネーションクリック
  session.find('div#ttlinfo-stry').find('p#page-list').click_link num.to_s
  sleep 3 # ajaxで内容が書き換えられる間少し待つ。待ち時間は適当...
  puts session.find('div#ttlinfo-stry').find('dt').text
end
$ ruby bandai.rb

また一つ望みが叶いました。
難しいことはまだまだですが、勉強になりました