AndroidによるHTMLのパース

先日書いたように、スクレイピングにはWebViewが使えるのだが、WebViewからjavascriptのメソッドを呼ぶ際にはどうしてもメインスレッドとは別スレッドで非同期で動作させる必要があるため、スクレイピング処理を外部からメソッドのように呼び出すことはできない。(スレッドをポーリングなどで監視したり、サービスからのコールバックを受けるようにすれば可能かもしれないが、非同期であることに変わりはない)

となると、やはり真っ当にHTMLを順にパースしていくのが良かろうと思ったが、そもそも適当なHTMLパーサが無いのがWebViewを使う大きな理由の一つな訳で何を使うか悩む所だ。

Javaで使える比較的軽量なHTMLパーサといえば

この辺か。一通り調べてみたが、結局Tagsoupを使用することにした。(次点はNekoHTML)
Tagsoupを選んだのはApache License、単独のjarで構成されている、SAXのインタフェースがある等という技術的なこともあるのだが、なんといってもAndroid SDK内部で実際に使用されているというのが大きな理由だ。

    • Android 2.2 SDKのHtmlクラス中で使用されるTagsoupのHTMLパーサ
import org.ccil.cowan.tagsoup.HTMLSchema;
import org.ccil.cowan.tagsoup.Parser;

Parser parser = new Parser();
try {
    parser.setProperty(Parser.schemaProperty, HtmlParser.schema);
} catch (org.xml.sax.SAXNotRecognizedException e) {
    // Should not happen.
    throw new RuntimeException(e);
} catch (org.xml.sax.SAXNotSupportedException e) {
    // Should not happen.
    throw new RuntimeException(e);
}

しかし、Android SDK内部で使用しているからといってそのまま使える訳ではない。
Adnroid SDKでは一部のパッケージは隠されており(勘弁して欲しいのだが、ポリシがあるのだろう)、android.jarにも含まれないため、コンパイルに失敗するのだ。

このように内部で使用していることが解っているクラスを使用する場合は、

1. リフレクション(イントロスペクション)から使用する
2. コンパイルには外部ライブラリィ(jar)を参照する

この二通りの方法があるが、今回は後者を選んだ。
Tagsoupはバイナリとソースコードがどちらもアーカイブ公開されているので、それらを外部ユーザライブラリィとして、Eclipseならプロジェクトから参照してやるだけで良い。※

Android側で参照されているバイナリとの違いがある場合、実機では動かないので注意が必要だ。
Androidパッケージ(apk)と共に配布する場合、Eclipseプロジェクトのassetsディレクトリにjarアーカイブをコピーする必要がある)

追記: 記事の日付を間違った(本来、7/2付けでアップするはずだった)ので日付を変えました。ブックマークに登録して頂いた方にはご面倒ですが再度登録してください。