uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

[HtmlUnit] HtmlUnit利用の落し穴

前にHtmlUnit賛歌という記事を書きました。この記事は「スクレイピングHtmlUnitを使おう」という趣旨でした。今回、結論が変るわけではないのですが、開発を通じて経験した留意点をちょっと書いてみます。

前の記事では以下のように書きました。

HtmlUnitでは、XPathを使う*3ことができるのですが、これも気に入りました。XPathはそれ自体汎用的で強力であるだけでなく、ブラウザと連携する他のツール(AutoPager Add-on(Chrome用もある)とかWebTest Recorder Sidebarでも使える)もあるのが強みです。

上は本来、間違いではありません。XPathは標準なので、ブラウザのadd-inやextensionで試しつつ作ったXPathを、HtmlUnitで使えます。しかし、今回、DOMの構造が、ブラウザが作るものと、HtmlUnitが呼び出しているであろうNekoHtmlパーサが作るものとで異る、という問題に直面しました*1

スクレイピング対象のWebページを構成するHTMLが、正しいHTMLなら、生成されるDOMが一意に定まり問題無いのですが、誤ったHTMLの場合、例えば閉じタグが無かったりした場合、生成されるDOMがパーサによって異なってきます。

XPathは標準なので、互換性があるのですが、対象のDOMが異なっていれば、当然得られる結果は異なってきます。

スクレイピング対象のWebページがきちんとしていれば問題ないのですが、一般にはそうではないのが世の常、思いきりはまりました。単純なページではスイスイXPathを作れるのに、3重、4重のテーブルとかを使ってるページ(肝心なページ)に限って問題がひょこっと含まれており、ブラウザで対話的にXPathを試せないのでview sourceしてやらざるを得ない*2という、空虚感のある結果になります。

HtmlUnitはエミュレーション対象のブラウザとバージョンを指定できるので、ひょっとしたら上のような問題に対応できるケースもあるのかもしれませんが、私が直面した問題については有効ではありませんでした。

ご報告までにでした。

*1:いわゆる「ブラウザ非互換」の問題なのですが、このレベルで浮上するのは、「表示や操作上問題はないが、DOMの構造が異る」という問題です。なぜなら、ブラウザの表示上や操作上問題がある非互換は、対象サイトの開発時に動作確認で解決されてしまっているからです。そしてスクレイピングの時に発覚し問題になるというわけです。そして発覚したタイミングでは「対象サイトのWebページを正しく修正する」という正しい対策が取れない状況である可能性が高いので、トホホということになるわけです。

*2:実際には簡易にXPathを試せるデバッグコンソールのようなものを作って試行錯誤を効率的にやれるような工夫をしました。