スクレイピングに挑戦したのでサンプルコードを公開。
スクレイピング楽しいね
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
# 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
わお!すごい
たったこれだけで望みが叶いました。
agent = Mechanize.new
search_page = agent.get('http://example.com')
p search_page.links[0].click
とすると、リンク先のページも取得できます。
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
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
また一つ望みが叶いました。
難しいことはまだまだですが、勉強になりました