95
97

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-04-26

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

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

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

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を実行できません。
あれっ、どうしよう :cold_sweat:

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

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

95
97
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
95
97

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?