Nokogiriでうまく解析できなかった場合の対処

2015 年 1 月 27 日 by 山平

Rubyでスクレイピングするなら、Nokogiriが定番です。
概ねDOMに忠実な実装でありながら、rubyらしく書きたいポイントは押さえている心憎いライブラリです。

ところが先日、Nokogiriを使ってWebページをスクレイピングしていた時に、上手くノードが取得できない場面に遭遇しましたので、備忘録としてここに残します。

まずは通常通りにタグを取得します。
この時のxpathはソースコードを確認して、絶対に存在するものが指定されています。

>> require 'nokogiri'
=> true
>> require 'open-uri'
=> true
>> url="http://hoge.fuga.com"
=> "http://hoge.fuga.com"
>> doc=Nokogiri::HTML(open(url){|f|f.read})
=> (割愛)
>> zzz=doc.xpath("//p[@class='zzz']")
=> []

タグが取得できていません。
一体なぜなのでしょうか。

色々と試してみた結果、どうやら原因は「難読化されたJavaScriptコード」のようです。
本来なら機械的な意味で無駄が少なくなっているはずなのですが、Nokogiriと相性が悪いのでしょうか。

仕方がないので、<script>〜</script>を正規表現で取り除きます。
元々NokogiriはJavaScriptを実行できないので、あまり問題ないと判断しました。

&gt;&gt; require 'nokogiri'
=&gt; true
&gt;&gt; require 'open-uri'
=&gt; true
&gt;&gt; url="http://hoge.fuga.com"
=&gt; "http://hoge.fuga.com"
&gt;&gt; html=(open(url){|f|f.read}).gsub!(/&lt;script[^&gt;]*&gt;.*?&lt;\/script&gt;/g, "")
=&gt; (割愛)
&gt;&gt; doc=Nokogiri::HTML(html)
=&gt; (割愛)
&gt;&gt; zzz=doc.xpath("//p[@class='zzz']")
=&gt; [&lt;Nokogiri::Node&gt;]

なお、最近はヘッダ要素内ではなく、HTML中や末尾にscriptタグを記述することが増えてきました。
このため、正規表現は最短マッチさせるように記述しないと、本来必要な要素まで削除してしまうので、注意が必要です。

以上です。

タグ: ,

TrackBack