Ruby + Nokogiriでスクレイピング

最近業務で使うことがあったのでスクレイピングのネタでQiita初投稿します。

```
この記事での実行環境は以下のようになっております

CentOS 6.8

$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]

$ nokogiri -v
# Nokogiri (1.6.8.1)
```

## What's スクレイピング?

>ウェブスクレイピング（英: Web scraping）とは、ウェブサイトから情報を抽出するコンピュータソフトウェア技術のこと。 ウェブ・クローラーあるいはウェブ・スパイダーとも呼ばれる。
https://ja.wikipedia.org/wiki/ウェブスクレイピング より引用

ようするに特定のウェブサイトからほしい情報を抜き取ることっすね！

## What's Nokogiri?
Rubyでスクレイピングするときの定番ライブラリ

公式サイト
http://www.nokogiri.org/

## 準備
まずは以下のコマンドでNokogiriをインストールしましょう

```
$ gem install nokogiri
Building native extensions.  This could take a while...
Successfully installed nokogiri-1.6.8.1
Parsing documentation for nokogiri-1.6.8.1
Done installing documentation for nokogiri after 3 seconds
1 gem installed
```
インストールに成功していれば、以下のコマンドでバージョンを確認できます

```
$ nokogiri -v
# Nokogiri (1.6.8.1)
    ---
    warnings: []
    nokogiri: 1.6.8.1
    ruby:
      version: 2.3.1
      platform: x86_64-linux
      description: ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
      engine: ruby
    libxml:
      binding: extension
      source: packaged
      libxml2_path: "/home/vagrant/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/nokogiri-1.6.8.1/ports/x86_64-pc-linux-gnu/libxml2/2.9.4"
      libxslt_path: "/home/vagrant/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/nokogiri-1.6.8.1/ports/x86_64-pc-linux-gnu/libxslt/1.1.29"
      libxml2_patches: []
      libxslt_patches: []
      compiled: 2.9.4
      loaded: 2.9.4
```
ファイルを作成してライブラリを読み込むための記述を追加します

```scrape.rb
require 'nokogiri'

# URLに簡単にアクセスできるようにするためのライブラリ
require 'open-uri'
# CSV出力をできるようにするためのライブラリ
require 'csv'
```

追加したgemをインストールしたら準備完了です

```
$ bundle install
```

## Let's スクレイピング！
今回はQiitaに投稿されているRubyに関する記事のタイトルを取得してみます

```scrape.rb
require 'nokogiri'
require 'open-uri'

url = 'https://qiita.com/search?q=ruby'

charset = nil

html = open(url) do |f|
    charset = f.charset
    f.read
end
  
doc = Nokogiri::HTML.parse(html, nil, charset)
doc.xpath('//h1[@class="searchResult_itemTitle"]').each do |node|
  p node.css('a').inner_text
end
```

出力結果

```
$ ruby scrape.rb
"RUBY"
"Rubyってなんだ"
"Rubyにないもの"
"Rubyだったら"
"Ruby"
"Ruby"
"【Ruby】Ruby入門：%記法について"
"RubyでRubyを描く"
"【Ruby】Ruby入門：クラスについて"
"Ruby | case と === の歴史 #ruby"
```

もうちょっといろいろやってみたいっすね
RubyとPHPとSwiftに関する記事のタイトルを取得してCSVに出力してみます

```scrape.rb
require 'nokogiri'
require 'open-uri'
require 'csv'

urls = %w(
  https://qiita.com/search?q=ruby,
  https://qiita.com/search?q=php,
  https://qiita.com/search?q=swift
)
titles = []

charset = nil
urls.each do |url|
  html = open(url) do |f|
    charset = f.charset
    f.read
  end

  doc = Nokogiri::HTML.parse(html, nil, charset)
  doc.xpath('//h1[@class="searchResult_itemTitle"]').each do |node|
    title = node.css('a').inner_text
    titles.push(title)
  end
end

CSV.open("qiita_title.csv", "w") do |csv|
  csv << titles
end
```

同じディレクトリにcsvファイルが作成されます

```qiita_titile.csv
Macport と anyenv を使っているときに ruby-build を使って最新の ruby をインストールする方法,Railsで新規プロジェクトを始めるまで,zero-server maps 日本語版,RailでCSVエクスポートする,Rubyでオブジェクトの中身を調べたい時によく使うメソッド,El Capitanでopenssl/ssl.h が無いとかいうエラーが出た場合,mini_exiftool で Exif を解析してレンズ名を取り出す,railsとtwilioで電話を掛けてみた,RUBY,Rubyってなんだ,PHP,PHP,phpでphpをはさむ方法,【PHP】PHP_EOL,PHP 配列　,herokuでPHP,PHP Basics,phpの型,Awesome PHP,PHP で setuidgid,swift,Swift,Swift の ?? ってなんだっけ,【Swift】Swiftのversionを確認しよう,[Swift] Swift Memo,Start Developing iOS Apps (Swift) 1-1,TableViewCellの右ずれを直す,代入と出力,Delegation,Swift で AppBank Fello を利用する
```

## まとめ
ぼくが実際に業務で行った作業は、サイト内のimgタグをスクレイピングして特定のパスに置換したものをCSVとして出力するというものでした。
初めてスクレイピングをやってみましたが、ほしいデータを取得して出力できたときは快感でした！
簡単かつ工夫次第でいろんなデータの取得ができるのでぜひ試してみてください！