箱のプログラミング日記。

渋谷の自社開発企業でRails書いてます。

Mechanizeでスクレイピング【Rails】

f:id:y_hakoiri:20191102121704j:plain

Mechanizeというgemを使用してスクレイピング(外部サイトから情報を取得する)を行う手順を書いていきます。

 

①Mechanizeをインストール
gem 'mechanize'

$ bundle install

 

②model配下にscraping.rbを作成

今回はスクレイピングで取ってきた要素をデータベースに保存するので

model配下にスクレイピング用のファイルを作成します。

 

③Scrapingクラスを記述

先ほど作ったscraping.rbでScrapingクラスを記述します。

Mechanizeをインストールしていることで、Scrapingクラスが使えるようになります

class Scraping
 agent = Mechanize.new
 current_page = agent.get("https://google.com")
 elements = current_page.search('.p-ranking__item a')
end

 

 

④getメソッドで該当ページのURLを取得

Meshanize.newでインスタンスを生成すると、そのインスタンスに対し

Mechanizeで定義されているメソッドが使えるようになります

 

getメソッドはブラウザからあるページを呼び出してくることができるメソッド

class Scraping
 agent = Mechanize.new
 current_page = agent.get("アドレス")
end

 

⑤searchメソッドでHTML要素を取得
class Scraping
 agent = Mechanize.new
 current_page = agent.get("アドレス")
 elements = current_page.search('.content a')
end

getメソッドに同じく、serchメソッドはMechanizeによって利用できるメソッドで

HTMLの中から、引数で指定した要素を取得することができます 

 

タグの他に、上記のように'.content'とすればクラス名で取得することもできます。

idの場合は'#content'

'.content a'の場合は、contentクラス配下のaタグを取得します。

 

スペースで区切ればいくつも重ねて指定することができるので、

親子構造を意識しつつ、適切にクラス名やタグを記述すれば

誤って意図しない要素を取得するのを防ぐことができます。

 

 

複数ある場合は配列の形で全て取得されるので

1つのみ取得したい場合はatメソッドを使用します(一番最初にヒットしたもののみ表示される)

 

⑥get_attributeで属性の値を取得。もしくはinner_textでテキストを取得

searchメソッド(もしくはatメソッド)で取得された値に対し、中身を取得する。

class Scraping
 agent = Mechanize.new
 current_page = agent.get("アドレス")
 elements = current_page.search('.content a')
 elements.each do |ele|
  link = ele.get_attribute('href')
  puts link
 end
end

 

複数ある場合は配列なのでeachメソッドを使用すると良い

 

データを保存する場合

①newでインスタンス生成、先ほど取得した値を引数に持たせる

この時すでにあるデータはDBに保存したく無い場合、newではなくwhere + first_or_initializeメソッドを使用する

first_or_initializeはwhereとともに使うと、引数にもたせた内容と同じデータを探し(where)た上で同じデータが無かったら作成してくれる

 

②newだけでは保存されないのでsave

 

③$console cでコンソールを立ち上げ、メソッドを実行

もしエラーが起きたりして途中でエディタを編集→再実行したい場合は

コンソールを再起動しないと反映されないのでreload!をすること。

 

最初irbで作業していたところ、NoMethodErrorで保存ができなかった。

結局エラーの原因は別のところにあったので多分直接的な原因では無いと思うけど、

データとのやりとりが必要な場合はirbではダメなのかな・・・?とちょっと思ったり(時間のある時に調べます)