今回はRubyのNokogiri
というGemを使って、スクレイピングをするときの大元となる準備をまとめました。
対象読者
- 大量のURLページに対してスクレイピングをしたいけど、やり方がわからない
- Rubyでスクレイピングしてみたい人
環境
- Ruby2.5.0
実装
- プロジェクトのディレクトリ構造は以下の通りです。
- Gemは
vendor/bundle
配下にインストールするようにします。
.
├── Gemfile
├── Gemfile.lock
├── main.rb
└── vendor/bundle/*
Gemインストール
- 以下のGemを入れましょう。
- 今回の主役となる
nokogiri
はもちろんですが、pry
を入れることでデバッグが楽になります。
gem 'nokogiri'
gem 'pry-byebug'
スクレイピングの為にページのHTMLをNokogiri::HTML::Document
に変換する
- では実際に動くコードを書いていきます。
- Nokogiriでスクレイピングする為には、ページのHTMLを材料にして、
Nokogiri::HTML::Document
というオブジェクトを作る必要があります。 - それを実現するのが、
Nokogiri::HTML.parse
メソッドです。
# htmlにはページのHTML(String型)が入る
Nokogiri::HTML.parse(html, nil, 'utf-8')
- ページのHTMLをString型として取得する方法なのですが、Rubyの
open-uri
を使う方法と、Shellのcurl
を使う方法とがあります。 - どちらでもいいのですが、以前
open-uri
だとうまく行かない場合があって、その時はcurl
の方を使いました。
# open-uriの場合
require 'open-uri'
html = open(url) { |f| f.read }
# curlの場合はkconvを使ってUTF-8にすること
require 'kconv'
html = `curl -s #{url}`.toutf8
- ではこれらを使って、「ページのURLを渡すと、
Nokogiri::HTML::Document
型にして返してくれるメソッド」を作りましょう。(今回はopen-uri
を使います。)
require 'open-uri'
def setup_doc(url)
charset = 'utf-8'
html = open(url) { |f| f.read }
doc = Nokogiri::HTML.parse(html, nil, charset)
# <br>タグを改行(\n)に変えて置くとスクレイピングしやすくなる。
doc.search('br').each { |n| n.replace("\n") }
doc
end
- これで第一ステップ完了です。
Nokogiri::HTML::Document
から、必要な情報を抽出する
- ページを
Nokogiri::HTML::Document
型にしたら、いよいよデータの抽出です。 - データの抽出には
XPath
というものを使います。(こちらに詳しく書いてありました!) - 具体例だとこんな感じになります。
# ページのNokogiri::HTML::Documentを取得。
doc = setup_doc(url)
# ページのタイトル名と、詳細ページへのURLを抽出する。
page_title = doc.xpath('div/h1').text
detail_url = doc.xpath('div/h2/a').attribute('href').value
- RubyのXPathでよく使う書き方については後日また書きます。
CSVへの出力
- 最後はCSVへの出力です。
- CSVに出力するには
csv
ライブラリを使います。 - CSVのファイルを開き(なければ自動で作成されます)、そこに必要な情報を格納した配列をpushしていくことで、CSVとして出力することができます。(配列内の順番は必ず揃えましょう)
require 'csv'
# CSVヘッダー
headers = ['Title', 'Detail URL', 'Page URL']
CSV.open('target.csv', 'w') do |csv|
# 一行目はCSVヘッダーにする
csv << headers
# 今回はデータが一つだけだが、for文とかでたくさんpushすることができる
csv << [page_title, detail_url, url]
end
まとめ
- 全体をまとめるとこういう感じになります。(
main.rb
に書きます) - 実装完了後、
ruby main.rb
を実行すれば、スクレイピングが実行されてCSVが出力されます。
require 'bundler/setup'
require 'nokogiri'
require 'open-uri'
require 'csv'
def setup_doc(url)
charset = 'utf-8'
html = open(url) { |f| f.read }
doc = Nokogiri::HTML.parse(html, nil, charset)
doc.search('br').each { |n| n.replace("\n") }
doc
end
def scrape(url)
doc = setup_doc(url)
page_title = doc.xpath('div/h1').text
detail_url = doc.xpath('div/h2/a').attribute('href').value
[page_title, detail_url, url]
end
if __FILE__ == $0
urls = [
'https://www.example1.com',
'https://www.example2.com',
'https://www.example3.com'
]
csv_header = ['ページタイトル', '詳細URL', 'URL']
CSV.open('result.csv', 'w') do |csv|
csv << csv_header
urls.each do |url|
begin
csv << scrape(url)
rescue
# エラー処理
# 例) csv << ['err', 'err', url]
end
end
end
end