RubyのプログラミングやUnitテストの書き方も少しづつ分かってきたので、少し応用編でRubyを使ったWebスクレイピングをしてみようと思います。スクレイピングというのは、どこぞのWebサイトで公開されているコンテンツを、プログラミングを使って手元にガポッと取ってくるというあれです。
まず、Nokogiriを手元のMacbook Airにインストールする
公式サイトのインストール方法説明を参考にします。例の通り英語サイトですが、最近意識して英語読むようにしてるので、アレルギー無く読めるようになってきました。
インストールは簡単で、
1 2 |
gem install nokogiri |
の一発で入るようです。このgemはRubyの外部ライブラリを管理してくれるパッケージマネージャーのようなものらしいですが、System領域にどんどんgemを入れていると管理が煩雑になってくる(と先人が警告している)ので、bundleというgemをプロジェクト単位で管理してくれるものを使ってnokogiriをインストールすることにします。
その前に、公式サイトの説明では、Macにlibxml2、libxsltという2つのライブラリを先に入れておいてねとの説明があるので、MacのパッケージマネージャであるHomebrewを使ってこの2つのライブラリを入れます。
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
まず、libxml2とlibxsltが入って無いことをチェック MyMBA:scraping_traning meguroman$ brew list -l | grep libx* drwxr-xr-x 4 meguroman admin 136 9 23 22:01 glib drwxr-xr-x 3 meguroman admin 102 8 28 14:29 libffi drwxr-xr-x 3 meguroman admin 102 7 30 18:03 libgpg-error drwxr-xr-x 3 meguroman admin 102 7 30 18:03 libksba drwxr-xr-x 3 meguroman admin 102 8 26 13:52 libmpc08 drwxr-xr-x 4 meguroman admin 136 8 28 14:28 libpng drwxr-xr-x 4 meguroman admin 136 9 23 22:02 libtiff drwxr-xr-x 3 meguroman admin 102 7 30 18:02 libtool drwxr-xr-x 3 meguroman admin 102 7 30 18:03 libyaml 無いのでインストール MyMBA:scraping_traning meguroman$ brew install libxml2 ==> Downloading https://homebrew.bintray.com/bottles/libxml2-2.9.2.yosemite.bottle.1.tar.gz ######################################################################## 100.0% ==> Pouring libxml2-2.9.2.yosemite.bottle.1.tar.gz ==> Caveats This formula is keg-only, which means it was not symlinked into /usr/local. OS X already provides this software and installing another version in parallel can cause all kinds of trouble. Generally there are no consequences of this for you. If you build your own software and it requires this formula, you'll need to add to your build variables: LDFLAGS: -L/usr/local/opt/libxml2/lib CPPFLAGS: -I/usr/local/opt/libxml2/include ==> Summary 🍺 /usr/local/Cellar/libxml2/2.9.2: 275 files, 11M MyMBA:scraping_traning meguroman$ brew install libxslt ==> Downloading https://homebrew.bintray.com/bottles/libxslt-1.1.28_1.yosemite.bottle.tar.gz ######################################################################## 100.0% ==> Pouring libxslt-1.1.28_1.yosemite.bottle.tar.gz ==> Caveats To allow the nokogiri gem to link against this libxslt run: gem install nokogiri -- --with-xslt-dir=/usr/local/opt/libxslt This formula is keg-only, which means it was not symlinked into /usr/local. OS X already provides this software and installing another version in parallel can cause all kinds of trouble. Generally there are no consequences of this for you. If you build your own software and it requires this formula, you'll need to add to your build variables: LDFLAGS: -L/usr/local/opt/libxslt/lib CPPFLAGS: -I/usr/local/opt/libxslt/include If you need Python to find bindings for this keg-only formula, run: echo /usr/local/opt/libxslt/lib/python2.7/site-packages >> /usr/local/lib/python2.7/site-packages/libxslt.pth mkdir -p /Users/meguroman/Library/Python/2.7/lib/python/site-packages echo 'import site; site.addsitedir("/usr/local/lib/python2.7/site-packages")' >> /Users/meguroman/Library/Python/2.7/lib/python/site-packages/homebrew.pth ==> Summary 🍺 /usr/local/Cellar/libxslt/1.1.28_1: 145 files, 3.3M 再度確認 MyMBA:scraping_traning meguroman$ brew list -l | grep libx* drwxr-xr-x 4 meguroman admin 136 9 23 22:01 glib drwxr-xr-x 3 meguroman admin 102 8 28 14:29 libffi drwxr-xr-x 3 meguroman admin 102 7 30 18:03 libgpg-error drwxr-xr-x 3 meguroman admin 102 7 30 18:03 libksba drwxr-xr-x 3 meguroman admin 102 8 26 13:52 libmpc08 drwxr-xr-x 4 meguroman admin 136 8 28 14:28 libpng drwxr-xr-x 4 meguroman admin 136 9 23 22:02 libtiff drwxr-xr-x 3 meguroman admin 102 7 30 18:02 libtool drwxr-xr-x 3 meguroman admin 102 9 29 14:55 libxml2 drwxr-xr-x 3 meguroman admin 102 9 29 14:57 libxslt drwxr-xr-x 3 meguroman admin 102 7 30 18:03 libyaml |
インストール完了とともに、ビールのマークが表示されます。作者さんの神経が分かりません。夕方疲れたころにこのマークは辞めてください。全てを捨ててビールを飲むために帰りたくなります。(゚A゚;)ゴクリ
次にBundleを使ってgemでnokogiriをインストールしていきます。まずは、カレントディレクトリをBundle管理のフォルダに指定が必要のようです。
1 2 3 |
MyMBA:scraping_traning meguroman$ bundle install --path . Could not locate Gemfile |
あとで知りましたが、–path には通常、vendor/bundleというディレクトリをプロジェクトごとに指定するのが通のようです。あと、bundleのプロジェクトごとの初期化はbundle initを使うようです。知らなかった…。
次に、gemの管理リストであるGemfileを作ります。(bundle initを使っていれば、Gemfileのガワが自動生成されます。)
Gemfile
1 2 3 |
source 'https://rubygems.org' gem 'nokogiri' |
そしたら、Bundleを使ってNokogiriをインストールします。
1 2 3 4 5 6 7 8 9 10 |
MyMBA:scraping_traning meguroman$ bundle install Fetching gem metadata from https://rubygems.org/......... Fetching version metadata from https://rubygems.org/.. Resolving dependencies... Installing mini_portile 0.6.2 Installing nokogiri 1.6.6.2 with native extensions Using bundler 1.10.6 Bundle complete! 1 Gemfile dependency, 3 gems now installed. Bundled gems are installed into .. |
このインストール3分くらい応答が帰って来なくて、やべ、フリーズか・・・と不安になりましたが、待ったらしっかりインストール完了してくれました。良かった。。ε-(´∀`*)
後から気付きましたが、すでにnokogiriがシステムに入ってたようで、nokogiri追加になってしまってました。bundle管理のnokogiriを使うにはbundle execを頭に付けて使うと良いようです。
1 2 3 4 5 |
MyMBA:scraping_traning meguroman$ which nokogiri /usr/bin/nokogiri MyMBA:scraping_traning meguroman$ bundle exec which nokogiri /Users/meguroman/GoogleDrive/WebSite/localServer/Training/rooter_training/scraping_traning/ruby/2.0.0/bin/nokogiri |
nokogiriでとにかうスクレイピングやってみる
ひとまずnokogiriの動作確認として、チュートリアルサイトの通りYahooのタイトル取得のプログラムを書いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
require 'open-uri' require 'nokogiri' #スクレイピング対象URL @url = 'http://www.yahoo.co.jp/' @html = open(@url) do |f| # 対象サイトの文字コード取得 @charset = f.charset # 対象サイトのHTML読み込み f.read end @doc = Nokogiri::HTML.parse(@html, nil, @charset) # タイトルを標準出力 puts @doc.title |
1 2 3 |
MyMBA:scraping_traning meguroman$ ruby get_site_title.rb Yahoo! JAPAN |
サイトの新着記事一覧から情報を取ってきて、タブ区切りファイルにまとめる
nokogiriのスクレイピングでは、HTML構造をてっぺんからたどっていくことで目的の情報を探し当てるというアプローチになりますが、基本的にはnokogiriのCSSメソッドを使うだけで必要十分なことができそうです。
情報サイトから新着記事一覧の、タイトル、画像URL、記事URLを取得するコードを以下のように作成しました。一点注意なのは、画像URLを取得するときにattribute(‘src’)で取ろうとすると、画像URLがダミーファイルに置き換えられる罠が隠されています。怖いですね。なので、attribute(‘data-original’)を指定する必要があります。
1 2 3 |
print node.css('img').attribute('src').value //=> /img/default/dummy.png print node.css('img').attribute('data-original').value //=> /image/AX0Q0026.jpg |
完成したコードは以下です。
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
require 'open-uri' require 'nokogiri' class Get_site_info # サイトから情報をスクレイピングで取得する # スクレイピングサイトからHTMLデータ取得 # @param [String] url スクレイピング対象URL # @return [Node] サイトHTMLノードオブジェクト def initialize(url) #スクレイピング対象URL @url = url #HTMLデータ取得 @html = open(@url) do |f| # 対象サイトの文字コード取得 @charset = f.charset # 対象サイトのHTML読み込み f.read end #HTMLデータのパース @doc = Nokogiri::HTML.parse(@html, nil, @charset) end # トラベル新着記事からタイトル、画像URL、記事URLを取得 def get_news_tvs # トラベル新着記事のノード取得 news_list = @doc.css('div.content_box') # 記事ごとにタイトル、画像URL、記事URLを取得し、タブ区切りで出力 news_list.each do |node| print node.css('h3').text + "\t" print node.css('img').attribute('data-original').value + "\t" print node.parent.attribute('href').value + "\n" end end end # スクレイピング実行 get_site_info = Get_site_info.new('http://ca-media.jp/travel') get_site_info.get_news_tvs |
このコードを実行すると以下の結果が得られます。
1 2 3 4 5 6 7 |
MyMBA:scraping_traning meguroman$ ruby get_site_info.rb 時差ボケ撃退!客室乗務員も実施している眠れない夜にすとんと眠る方法 /image/AX0Q0026.jpg /life-style/report282 初めてでも大満喫!ユニバーサルスタジオジャパンの周り方 /image/4085.jpg /travel/report258 女性必見!羽田空港の免税店で買うべき化粧品ブランドとは☆ /image/3830.jpg /beauty/report133 スペインのベストシーズンはいつ?スペインの天候情報 /image/4097.jpg /travel/report262 大自然のアクティビティと柚子朝食~星野リゾートオーベルジュ&スパUTOCO滞在vol.3~ /image/3935.jpg /travel/report231 |
スクレイピングの応用編はまた次回