読者です 読者をやめる 読者になる 読者になる

MozillaのスクレイピングフレームワークFathomを試してみる

こちらのOSDNの記事で知ったのですが、MozillaでFathomというJavaScript用のスクレイピングフレームワークを開発しているようです。仕事でクローラーを作ったりしていたこともあり、面白そうだと思ったので軽く調べてみました。

mag.osdn.jp

以下のGitHubリポジトリで開発されています。GitHub Pagesに詳しいドキュメントもあります。

github.com

OSDNの記事で触れられている開発者のErik Rose氏のブログエントリはこちら。

hacks.mozilla.org

ドキュメントやErikさんのブログエントリなどをざっと眺めてみたところ、それほど複雑なものではなく、ある程度曖昧なルールとスコアリングを定義しておき、最もスコアの高い要素の選択するというのが基本的なコンセプトのようです。

なにはともあれ試してみます。まずは適当なディレクトリを掘り、npmでFathomとjsdomをインストールします。

$ npm install fathom-web
$ npm install jsdom

プログラムはこんな感じです。FathomのドキュメントのBasic Useに記載されているものをベースにしています。

const {dom, props, out, rule, ruleset, score, type} = require('fathom-web');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;

function containsColonsOrDashes(element){
  // 要素にコロン(:)かダッシュ(-)が含まれてたらtrueを返す
}

const rules = ruleset(
  // titeタグ、スコアは1
  rule(dom('title'), type('titley')),
  // OpenGraphのmetaタグ、スコアは2
  rule(dom('meta[property="og:title"]'), type('titley').score(2)),
  // タイトルにコロン(:)かダッシュ(-)が含まれている場合は
  // ナビゲーション用っぽいのでペナルティとしてスコアを×0.5する
  rule(type('titley'), score(fnode => containsColonsOrDashes(fnode.element) ? .5 : 1)),
  // スコアが最も高いものをtitleキーとして提供する
  rule(type('titley').max(), out('title'))
);

// jsdomでDOMツリーを生成
const { document } = (new JSDOM('<html>...</html>')).window;
// 指定したDOMツリーに対する適用結果を取得
const facts = rules.against(document);

// 最もスコアの高いノードを取得してコンソールに表示
const bestTitleFnode = facts.get('title');
console.log(bestTitleFnode[0].element);

見ての通り、そんなに難しいことはしていません。上記のコードでは最もスコアの高い要素を取り出していますが、ルールにマッチした要素をすべて取得したり、要素からスコアを取得したりということもできます。

ルールの定義の仕方次第かもしれませんが、タイトルなどわかりやすいものはともかくデータとして使用する目的でスクレイピングするにはある程度きちんと論理的なマークアップがされていないとこのアプローチでは厳しいのではないかという気もします。ちゃんと使ってみないとなんとも言えない感じですね。実際は要素を取り出した後の切り出しや加工も必要だったりしますし…。

とはいえ、スコアリングの最適化機能など面白い機能もあるので時間があるときにもう少しちゃんとしたデータを使って試してみたいところです。