このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

Webページからの情報抽出について考えみた

Webページ(HTML文書)からの情報抽出は、古くからある話題です。そして、「頑張れば何とかなるけど楽な方法はないよね」というあたりに落ち着く話題でもあります。「頑張るのは辛い ←→ 楽して出来ることはたかが知れてる」というトレードオフの関係なのです。このトレードオフの境界線をズラして、「楽に出来るけど、けっこうなところまでイケる」としたいな、と思います。

XSLTをものすごく単純化してみる

汎用プログラミング言語でHTMLをパーズしていじれば何でもできますが、それは楽ではないですね。HTML文書からの変換処理に向いた言語といえばXSLTです。XSLTは、基本的には XML to XML の変換を扱うので、入力HTML文書をXML(XHTML)化する前処理(またはオプション)が必要です。いったんXML文書ツリーができてしまえば、XSLTの変換能力は豊富で強力です。

問題は、XSLTが難しいことです。習得してしまえば無敵の武器かも知れませんが、学習は容易ではありません。「アレを勉強するくらいなら汎用プログラミング言語でやるよ」と思う人も多いでしょう。

XSLTでは、入力とのパターンマッチをXPathで行い、出力データとXSLTの変数/命令/関数などをXML名前空間で区別しながら混在させて書きます。入力のパターン、処理自体の記述、出力のデータを一緒に書くところが、便利である反面ややこしくなっているところです。

入力はHTMLだとして、入力データとのパターンマッチはCSSセレクターを使ってはどうでしょう。CSSセレクターはXPathほどの能力は持ちませんが、非常に多くの人が使っていてお馴染みなものです。学習の負担もXPathよりはずっと小さいでしょう。

そして、出力はJSONに限定したらどうでしょう。JSONの複合データは、ブラケット('[' と ']')で囲まれた配列か、ブレイス('{' と '}')で囲まれたオブジェクトだけです。XMLのような様々なタグや属性はないので、出力データの記述は極端に単純化されます。

命令や関数は使いません。パターンマッチした結果を組み合わせて出力するだけです。それ以上の処理は、結果であるJSONデータに対して行えばいいと割り切ります。JSONに対する処理なら、どんなプログラミング言語でも出来ます。

XSLTの概念と機能を、「XPath → CSSセレクター」「出力XML → 出力JSON」「命令/関数 → なし」と単純化したらイイんじゃないか? と、実際にやってみました。単純化するので低機能になりますが、トレードオフの境界線をズラす効果はあるように思えます。「楽に出来るけど、けっこうなところまでイケる」みたい。

簡単な実例

今日は詳しいことを述べませんが、いくつかの簡単な実例をあげます。(処理系は実際に動いていて、割と複雑な変換もできます。)

最初に出現する見出し(h1からh4のどれか)の内容テキスト:↓

 <h1, h2, h3, h4>$:text</>

すべての画像のURL(src属性値)のリスト:↓

 *<img>$src</>

すべての見出し(h1からh6のどれか)の、タグと内容HTMLのタプルからなるリスト:↓

 *<h1, h2, h3, h4, h5, h6>$:tag, $:html</>

すべての「div要素の子である見出し(h1からh4のどれか)」の、タグと内容HTMLをプロパティとするオブジェクトからなるリスト:↓

 *<div> ><h1, h2, h3, h4>"tag": $:tag, "content": $:html</></>

最初に出現したテーブルの(テキストとしての)セルデータを、入れ子にしたリスト:↓

 <table>
  *<tr> *<th, td>$:text</> </>
 </>

すべての要素のタグと属性を出現順に列挙したリスト:↓

 *<*>$:tag, $:attrs</>