すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Rails

公開日:  |  最終更新日:

【Rails】 Mechanizeを使ってスクレイピングをしよう

ぴっかちゃん
ぴっかちゃん

Mechanizeは、スクレイピングを簡単に実装することができるgemです。このgemを使うと、Webページをプログラムで操作し、情報を取得することができます。

Mechanizeとは

Mechanizeは、スクレイピング用のgemです。Webサイトからデータを抽出したり、フォームに自動的に入力して送信したりするのに便利です。このgemを使うと、WebサイトをRubyのコードで操作し、情報を取得することができます。

スクレイピングとは

スクレイピングは、Webサイトから自動的にデータを収集する技術です。特定のサイトから自分が欲しい情報のみを効率的に取得する際に役立ちます。

例えば、特定のテーマやキーワードに関するニュース記事を複数のニュースサイトから集めて、自分用のニュースサイトを作成する場合です。スクレイピングを使うことで自動化することができ、複数のサイトを巡る手間を省くことができます。

導入方法

まずは、MechanizeをインストールするためにGemfileに以下のコードを追記し、budle installコマンドでインストールします。

Gemfile | Mechanizeを追加
1
gem 'mechanize'

基本的な使い方

Mechanizeを使うには、以下のようにMechanizeクラスのインスタンスを作成します。

インスタンスの作成
1
agent = Mechanize.new

このインスタンスに対して、Mechanizeが提供するメソッドを使用してデータの収集などを行います。データ収集にはHTMLの構造を確認する必要があるため、ブラウザの検証モードを利用して、取得したいデータにどのようにアプローチするかを考えることが重要です。

Webページへのアクセス

まずはスクレイピングするWebサイトにアクセスする必要があります。その際に使うのがgetメソッドです。引数にはWebサイトのURLを渡します。

以下のように先ほど作成したMechanizeクラスのインスタンスに対し、getメソッドを使用します。

Webページへのアクセス
1
page = agent.get('https://example.com')

データの取得方法

先ほど作成したpageの中にスクレイピングするWebサイトの情報が入っています。この変数にMechanizeで定義されているメソッドを使って、Webページのさまざまな情報を取得することができます。

titleメソッド

スクレイピングをするWebサイトのタイトルを取得するメソッドです。

titleメソッド
1
2
3
4
5
6
agent = Mechanize.new
page = agent.get('https://www.yahoo.co.jp/')
title = page.title
puts title => "Yahoo! JAPAN"

titleメソッド

このようにHTMLのtitleタグのテキストを取得することができます。

searchメソッド

スクレイピングをするWebページ内の特定の複数の要素を取得するメソッドです。
引数にはCSSセレクタを渡します。返り値は配列になります。

HTMLの例
1
2
3
<div class="example">具体例1</div>
<div class="example">具体例2</div>
<div class="example">具体例3</div>
searchメソッド
1
2
3
4
5
6
7
8
9
10
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')
elements = page.search(".example")
p elements => [ <div class="example">具体例1</div>, <div class="example">具体例2</div>, <div class="example">具体例3</div> ]

スクレイピングでは、自分が欲しい情報をピンポイントで取得するため、CSSセレクタを細かく設定することがほとんどです。例えば、以下のHTMLから「サブセクション3.1の内容です」と「サブセクション3.2の内容です」のテキストコンテンツを取得する場合などです。

すべてのpタグにはcontentというクラスが付与されているため、クラス名だけでは目的の要素を特定することができません。

HTMLの例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div class="container">
  <div class="section" id="section1">
    <h2>セクション1</h2>
    <p class="content">セクション1の内容です</p>
  </div>
  <div class="section" id="section2">
    <h2>セクション2</h2>
    <p class="content">セクション2の内容です</p>
  </div>
  <div class="section" id="section3">
    <h2>セクション3</h2>
    <div class="subsection">
      <h3>サブセクション3.1</h3>
<p class="content">サブセクション3.1の内容です</p>
</div> <div class="subsection"> <h3>サブセクション3.2</h3>
<p class="content">サブセクション3.2の内容です</p>
</div> </div> </div>

そのため以下のように半角スペースで区切ることで階層構造を絞り込み、ターゲットとなる要素を指定します。

searchメソッド
1
subsections = page.search('.section .subsection .content')

atメソッド

スクレイピングをするWebページ内の特定の要素を1つだけ取得するメソッドです。
引数にはCSSセレクタを渡します。要素が複数存在する場合は一致する最初の要素のみを取得します。

HTMLの例
1
2
3
<div class="example">具体例1</div>
<div class="example">具体例2</div>
<div class="example">具体例3</div>
atメソッド
1
2
3
4
5
6
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')
element = page.at(".example")
puts element => <div class="example">具体例1</div>

inner_textメソッド

取得した要素のテキストコンテンツを取得するメソッドです。

HTMLの例
1
2
3
<div class="example">具体例1</div>
<div class="example">具体例2</div>
<div class="example">具体例3</div>
inner_textメソッド
1
2
3
4
5
6
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')
element = page.at(".example")

p element.inner_text
=> "具体例1"

searchメソッドを使って複数の要素を取得した場合は、以下のようにすると要素のテキストコンテンツのみが入った配列を作成することができます。

inner_textメソッド
1
2
3
4
5
6
7
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')
elements = page.search(".example")
elements_texts = elements.map(&:inner_text)
p elements_texts => ["具体例1", "具体例2", "具体例3"]

get_attributeメソッド

取得した要素のタグの属性を取得するメソッドです。

HTMLの例
1
2
3
4
5
<div class="content">
  <a href="https://example.com" class="link">Example Link</a>
  <a href="https://another-example.com" class="link">Another Example Link</a>
  <img src="image.jpg" alt="サンプル画像" class="image">
</div>
get_attribute
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')
links = page.search('.link')
images = page.search('.image')

links.each do |link|
href = link.get_attribute('href')
puts href end # 出力結果 # https://example.com # https://another-example.com images.each do |image|
src = image.get_attribute('src')
puts src end # 出力結果 # image.jpg

このようにaタグのhref属性の値や、imgタグのsrc属性の値を取得することができます。
また以下のように省略して書くこともできます。

省略した書き方
1
2
3
4
5
6
7
# 省略しない書き方
link.get_attribute('href')
image.get_attribute('src')

# 省略した書き方
link[:href]
image[:src]

リンクを辿る方法

この章ではリンク先のページをスクレイピングする際に便利なメソッドを紹介します。

link_withメソッド

ページ内のリンクを検索し、指定した条件に一致する最初のリンクのテキストとURLを取得するメソッドです。
取得した値に対して、textメソッドを使うとリンクのテキストコンテンツを、hrefメソッドを使うとリンクのURLを取得することができます。

基本的な使い方
1
2
3
4
5
6
7
link = page.link_with(検索する属性: 検索する名前)

p link.text
=> 取得したリンクのテキストコンテンツ

p link.href
=> 取得したリンクのURL

引数のキーは以下の属性を指定できます。

属性 検索するもの
text リンクのテキスト
href リンクのURL
class リンクのクラス属性
id リンクのid属性

以下が具体的な使い方です。

HTMLの例
1
2
3
<a href="https://example.com" class="external-link">Example Link</a>
<a href="https://another-example.com" class="external-link">Another Example Link</a>
<a id="special-link" href="https://special-example.com">Special Example Link</a>
link_withメソッド
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')

link_by_text = page.link_with(text: 'Example Link')
link_by_href = page.link_with(href: 'https://another-example.com')
link_by_class = page.link_with(class: 'external-link')
link_by_id = page.link_with(id: 'special-link')
p link_by_text.text => "Example Link" p link_by_text.href => "https://example.com" p link_by_href.text => "Another Example Link" p link_by_href.href => "https://another-example.com" p link_by_class.text => "Example Link" p link_by_class.href => "https://example.com" p link_by_id.text => "Special Example Link" p link_by_id.href => "https://special-example.com"

linksメソッド

link_withメソッドが指定した条件に一致する最初のリンクを取得するのに対し、ページ内の全てのリンクを配列として取得するメソッドです。リンクの一覧を取得したいときに便利です。

HTMLの例
1
2
3
<a href="https://example.com" class="external-link">Example Link</a>
<a href="https://another-example.com" class="external-link">Another Example Link</a>
<a id="special-link" href="https://special-example.com">Special Example Link</a>
linksメソッド
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')

links = page.links
p links => [ #<Mechanize::Page::Link "Example Link" "https://example.com">, #<Mechanize::Page::Link "Another Example Link" "https://another-example.com">, #<Mechanize::Page::Link "Special Example Link" "https://special-example.com"> ] links_texts = links.map(&:text) p links_texts => ["Example Link", "Another Example Link", "Special Example Link"] links_href = links.map(&:href) p links_href => ["https://example.com", "https://another-example.com", "https://special-example.com"]

clickメソッド

取得したリンクをクリックした結果としてリンク先のページの情報を取得するメソッドです。link_withメソッドと組み合わせて使います。

clickメソッド
1
2
link = page.link_with(text: 'Example Link')
next_page = link.click

clickメソッドを使うことで、特定のリンクをクリックした後のページ情報を取得し、さらなるスクレイピングを実行することができます。

フォームを送信する

この章ではページ内のフォームを送信するまでの流れを解説します。

form_withメソッド

ページ内のフォームを検索し、指定した条件に一致するフォームを取得するメソッドです。取得したフォームに対してデータを入力することができます。

基本的な使い方
1
page.form_with(検索する属性: 検索する名前)

引数のキーには以下の属性を指定できます。

属性 検索するもの
name フォームの名前
id フォームのid
method フォームの送信方法(GETまたはPOST)
action フォームのアクション属性

取得したフォームの各入力フィールドには、以下のようにして値を入力することができます。

入力フィールドに値を入力
1
2
3
form = page.form_with(name: 'search_form')

form['inputタグのname属性'] = 入力する値

以下が具体的な使い方です。

HTMLの例
1
2
3
4
5
<form action="/search" method="get" id="search-form" name="search_form">
  <input type="text" name="name" value="">
  <input type="text" name="email" value="">
  <input type="submit" value="検索">
</form>
form_withメソッド
1
2
3
4
5
6
7
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')
form = page.form_with(name: 'search_form')
# 取得したフォームの入力フィールドに値を入力
form['name'] = 'Pikawaka'
form['email'] = 'pikawaka@example.com'

button_withメソッド

ページ内の特定のボタン要素を取得するためのメソッドです。このメソッドを使用すると、特定のボタンをクリックして遷移するページの情報を取得することができます。フォームに複数の送信ボタンがある場合に便利です。

基本的な使い方
1
form.button_with(検索する属性: 検索する名前)

引数のキーには以下の属性を指定できます。

属性 検索するもの
name ボタンのname属性
value ボタンのvalue属性

以下は簡単な例です。

HTMLの例
1
<button name="next-button" onclick="location.href='/next_page'">次のページへ</button>
button_withメソッド
1
2
3
4
5
6
7
8
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')

# 'name'属性が 'next-button' であるボタンを取得
next_button = page.button_with(name: 'next-button')
# 遷移先のページ情報を取得 next_page = next_button.click

取得したボタンには以下のメソッドを使うことができます。

メソッド 取得できる値
name ボタンのname属性
value ボタンのvalue属性
type ボタンのtype属性
node ボタンのHTMLノード

以下が具体例です。

HTMLの例
1
2
3
4
5
6
7
<form id="user-form" name="user_form" action="/submit" method="post">
  <input type="text" name="name" value="">
  <input type="text" name="email" value="">
  <input type="submit" name="submit_button" value="送信1">
  <input type="submit" name="submit_button" value="送信2">
  <button type="submit" name="submit_button" value="送信3">submit3</button>
</form>
button_withメソッド
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
agent = Mechanize.new
page = agent.get('上記WebサイトのURL')
form = page.form_with(name: 'user_form')

# 'value'属性が '送信1' であるボタンを取得
submit_button1 = form.button_with(value: '送信1')
# 'value'属性が '送信3' であるボタンを取得
submit_button3 = form.button_with(value: '送信3')
p submit_button1.name
=> "submit_button"
p submit_button1.value
=> "送信1"
p submit_button1.type
=> "submit"
p submit_button1.node
=> #<Nokogiri::XML::Element:0xbd60 name="input" attribute_nodes=[#<Nokogiri::XML::Attr:0xbd24 name="type" value="submit">, #<Nokogiri::XML::Attr:0xbd38 name="name" value="submit_button">, #<Nokogiri::XML::Attr:0xbd4c name="value" value="送信1">]>

buttonタグで作成されたボタンのテキストは、タグの間に記述した内容になります。一方、inputタグにtype="submit"を指定して送信ボタンとした場合、ボタンのテキストはvalue属性で定義されます。

See the Pen rails_mechanize_01 by miyajima yuya (@pikawaka) on CodePen.

そのため、nodeメソッドを使用してbutton要素のテキストを取得できますが、input要素には対応するテキストがありません。取得しようとすると空文字になるので注意しましょう。その場合は、value属性を使ってボタンのテキストを取得してください。

input type=submitの場合
1
2
3
4
5
6
7
8
9
10
# buttonタグのテキストを取得
p submit_button3.node.text
=> "submit3"

# inputタグのテキストを取得
p submit_button1.node.text
=> ""

p submit_button1.value
=> "送信2"

submitメソッド

フォームを送信する際に使用するメソッドです。取得したフォームに入力されたデータを送信し、送信後のページ情報を取得することができます。

submitメソッド
1
2
3
4
5
6
7
8
9
agent = Mechanize.new
page = agent.get('WebサイトのURL')
form = page.form_with(name: 'search_form')

form['name'] = 'Pikawaka'
form['email'] = 'pikawaka@example.com'

# フォームを送信して次のページ情報を取得
next_page = form.submit

submitメソッドには引数を渡すことができます。button_withメソッドで取得したボタン要素を渡すと、submit時に特定のボタンを指定することができます。フォーム内に複数のボタンがあるときに便利です。

submitメソッドの引数
1
2
submit_button = form.button_with(value: '送信1')
form.submit(submit_button)

注意点

スクレイピングを行う際の注意点を紹介します。

ウェブサイトの利用規約を確認する

Webサイトの中にはスクレイピングを禁止しているサイトがあります。スクレイピングを行う前に、スクレイピングを許可しているか、禁止しているか利用規約の確認をしましょう。

負荷を最小限にする

短時間に大量のスクレイピングしてしまうとスクレイピングするサイトのサーバーにかなりの負荷をかけてしまい、迷惑をかけてしまう恐れがあります。リクエストの間に適切な間隔を設ける(例えば、1〜2秒のスリープを挟む)などの処理をしましょう。

また大量のデータを取得する際は、一度にすべてを取得するのではなく、分割して取得する方法を検討しましょう。

この記事のまとめ

  • Mechanizeはスクレイピングする際に便利なgemです。
  • スクレイピングを使うことで自動でWebサイトから欲しい情報を取得することができます。
  • スクレイピングが禁止されているサイトもあるので、使う前に必ず確認をしましょう。