休日にノコギリ使って日曜大工ではなく日曜プログラミングをやってみました。
Nokogiriって
スクレイピングとはWebサイトから情報を抽出するコンピュータソフトウェア技術のことです。 Nokogiri はスクレイピングに便利なRubyのgem(ライブラリ)です。 スクレイプとは「こすり落とす、削り取る」などの意味なのでNokogiri(鋸)という名前なんですねー
スクレイピングはややデリケートなもので、記事ネタにしにくい部分もあり、大抵の場合コピーして無断転載はアウトで著作権法第47条の7では「情報解析のための複製等」ならOKという感じですが、スクレイピング対象のWebサイトの利用規約に反する場合もあるので注意して利用したほうが無難と思います。 もちろん負荷をかけてしまうと攻撃とみなされてしまう可能性があるので十分に注意が必要となります。
今回はググったら上位にヒットする http://morizyun.github.io/blog/ruby-nokogiri-scraping-tutorial/index.html を参考にやってみました。
# URLにアクセスするためのライブラリの読み込み
require 'open-uri'
# Nokogiriライブラリの読み込み
require 'nokogiri'
# スクレイピング先のURL
url = 'http://example.jp/'
charset = nil
html = open(url) do |f|
charset = f.charset # 文字種別を取得
f.read # htmlを読み込んで変数htmlに渡す
end
# htmlをパース(解析)してオブジェクトを生成
doc = Nokogiri::HTML.parse(html, nil, charset)
# タイトルを表示
p doc.title
HTTPヘッダからcharsetを読み込んで、readメソッドでBodyを読み込んでいる動きです。
コマンドプロントから実行
$ ruby mojibake.rb
"\u0083t\u0083@\u0083b\u0083V\u0083\u0087\u0083\u0093\u0092Ê\u0094ÌEXAMPLE"
文字化けした結果が返ってくる・・・ この場合、HTTPレスポンスヘッダのcontent-typeで文字コードが取れないため判定できず、HTMLのmetaタグのcharsetがshift_jisのため、文字化けした結果が出力されているようです。 HTTPヘッダのContent-Typeや、htmlのmetaタグをどのように判定に使うかで期待する結果が得られないことが理解できました。
対処方
文字種別の判定をやめてNokogiri側でパースする部分を修正したところ文字化けは解消されました。
# URLにアクセスするためのライブラリの読み込み
require 'open-uri'
# Nokogiriライブラリの読み込み
require 'nokogiri'
# スクレイピング先のURL
url = 'http://example.jp/'
html = open(url).read
# htmlをパース(解析)してオブジェクトを生成
doc = Nokogiri::HTML.parse(html)
# タイトルを表示
p doc.title
Nokogiriのドキュメントによるとcharsetを指定しない場合、文字コードはlibxml2の自動判別に頼ることになるようです。Nokogiriドキュメント
Nokogiriでは常に文字列をUTF-8として内部的に格納するようで、世の中の多くのサイトはUTF-8を指定していると思いますので問題が起きにくいとは思います。 ただし、対象のWebサイトのHTTPヘッダからcharsetが返ってきているようであれば、指定したほうが確実です。
はい、勉強になりました。
清崎康史
レコチョクでサービス立ち上げから運用までさまざまな経験を経て、最近ではプロダクト品質と向き合い、日々奮闘中です。