HTML parsing by Ruby

Rubyのライブラリ「Nokogiri」を使って、HTML parsingをやってみることにします。

<僕が使っている環境>
ruby 2.0.0p247 (32bit)
DevKit-mingw64-32-4.7.2-20130224-1151-sfx (32bit)
nokogiri (1.6.0 x86-mingw32)
Windows7 (64bit)


(1)はじめに
もともと僕は、ruby 2.0.0p247 (64bit)を使っていました。ですが、64bit版を使っていると、Nokogiriのインストールで以下のようなエラーが発生して、うまくいきませんでした。

>gem install nokogiri

Fetching: mini_portile-0.5.2.gem (100%)
Successfully installed mini_portile-0.5.2
Fetching: nokogiri-1.6.0.gem (100%)
Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
ERROR:  Error installing nokogiri:
        ERROR: Failed to build gem native extension.

    C:/work_Apps/Ruby/ruby-2.0.0-p247-x64-mingw32/bin/ruby.exe extconf.rb
checking for libxml/parser.h... no
-----
libxml2 is missing.  please visit http://nokogiri.org/tutorials/installing_nokogiri.html for help with installing dependencies.
-----
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
  :   :
   (中略)

Gem files will remain installed in C:/work_Apps/Ruby/ruby-2.0.0-p247-x64-mingw32/lib/ruby/gems/2.0.0/gems/nokogiri-1.6.0 for inspection.
Results logged to C:/work_Apps/Ruby/ruby-2.0.0-p247-x64-mingw32/lib/ruby/gems/2.0.0/gems/nokogiri-1.6.0/ext/nokogiri/gem_make.out

libxml2が見つからないというエラーだったので、libxml2のインストール方法などなどを調べてみたものの、結局、解決しませんでした。

で、別の方向でいろいろ調べていたら、
Nokogiri does not yet support the 64-bit version of Ruby 2.0.0.
という情報を発見。
(参考) http://stackoverflow.com/questions/17280884/cant-install-nokogiri-for-ruby-in-windows
(参考) http://stackoverflow.com/questions/15320462/error-installing-nokogiri

そこで、32bit版のRuby2.0.0にしてみたら、Nokogiriのインストールがうまくいきました。
僕が使っているのは、「One-Click Ruby Installer for Windows」版です。
ruby_installer


(2)Nokogiriのインストール
gemでインストールします。
すると、以下の2つのライブラリがインストールされました。
mini_portile (0.5.2)
nokogiri (1.6.0 x86-mingw32)

> gem install nokogiri

Fetching: mini_portile-0.5.2.gem (100%)
Successfully installed mini_portile-0.5.2
Fetching: nokogiri-1.6.0-x86-mingw32.gem (100%)
Successfully installed nokogiri-1.6.0-x86-mingw32
Parsing documentation for mini_portile-0.5.2
Installing ri documentation for mini_portile-0.5.2
Parsing documentation for nokogiri-1.6.0-x86-mingw32
unable to convert "\x90" from ASCII-8BIT to UTF-8 for lib/nokogiri/1.9/nokogiri.so, skipping
unable to convert "\x90" from ASCII-8BIT to UTF-8 for lib/nokogiri/2.0/nokogiri.so, skipping
Installing ri documentation for nokogiri-1.6.0-x86-mingw32
2 gems installed

> gem list

*** LOCAL GEMS ***

bigdecimal (1.2.0)
io-console (0.4.2)
json (1.7.7)
mini_portile (0.5.2)
minitest (4.3.2)
nokogiri (1.6.0 x86-mingw32)
psych (2.0.0)
rake (0.9.6)
rdoc (4.0.0)
test-unit (2.0.0.0)

(3)使ってみる
とりあえず、Twitterのつぶやきを取ってみようかと思います。誰でもいいんだけど、今回は、孫正義さんのツイートにしてみます。

URLは、https://twitter.com/masason となり、HTTPSでアクセスすることになります。
しかし、

page=open('https://twitter.com/masason')

として、アクセスすると、SSLのエラーが発生します。

SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (OpenSSL::SSL::SSLError)

そのため、今回は、「証明書を検証をしない」設定でアクセスすることにしました。
(参考) mofu犬blog: [Ruby] open-uri の HTTPS リクエストで certificate verify failed:
(参考) mofu犬blog: [Ruby] デフォルトの CA 証明書ファイルを変更しても、証明書の検証に失敗する:

あと、文字コードも指定しています。

require 'nokogiri'
require 'open-uri'
require 'openssl'

page=open('https://twitter.com/masason', :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE)
html = Nokogiri::HTML(page.read, nil, 'UTF-8')

次に、取得したいツイート内容が、HTMLソースの中でどうなっているか見てみます。
ツイッターのWeb画面のHTMLソースから、ツイート1件分のところを見てみると、以下のような感じになっています。
tweet_html

<div class=”content”> タグの中に、ツイートの時刻と本文が収まっています。
その中の、<small class=”time”>タグの中の、<a>タグの中の、title属性に、時刻が入っています。
そして、<p class=”js-tweet-text tweet-text”>タグの中に、ツイート本文が入っています。

これらを踏まえてコーディングするとこんな感じ。

html.search('div.content').each do |content|
  # tweet時間の表示
  a=content.css('small.time a').first
  puts a.attribute("title").value

  # tweet本文の表示
  p=content.css('p.js-tweet-text.tweet-text').first
  puts p.content
end

(4)コーディングまとめ
最終的に作成したコードは、以下のようになりました。
僕の場合、AptanaStudioで動かしてるので、1行目の「#!/usr/bin/ruby」は適当です。

#!/usr/bin/ruby
# -- coding: utf-8

require 'nokogiri'
require 'open-uri'
require 'openssl'

page=open('https://twitter.com/masason', :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE)
html = Nokogiri::HTML(page.read, nil, 'UTF-8')

html.search('div.content').each do |content|
  puts "-" * 30

  # tweet時間の表示
  a=content.css('small.time a').first
  puts a.attribute("title").value

  # tweet本文の表示
  p=content.css('p.js-tweet-text.tweet-text').first
  puts p.content

end

実行するとこんな感じで、標準出力に返ってきます。

------------------------------
2013年10月22日 - 7:39
昨日、我が社の笠井(76歳)さんが亡くなられた。
笠井さんは、私の父の様な兄の様な方。企業買収や投資に必要な財務戦略や、資金調達に多大な力を発揮。笠井さん無しに今日のソフトバンクは存立していない。心より感謝し、ご冥福をお祈りいたします。
------------------------------
2013年10月15日 - 6:18
夢さえあれば朝起きるのが楽しい。
------------------------------
2013年10月14日 - 7:42
物事の解決策は常に複数ある。
一つにこだわり過ぎてはならない。
  :    :

Leave a comment