はてなブックマークの概要取得の処理

  • はてなブックマークが取得する概要は、本文ではなく Feed から取得している
    • よって、 Feed に含まれない範囲の過去の記事は概要が取得されない
  • Feed を提供していてもそれから正しく概要を取得するとは限らない

簡単にまとめるとこのようなことになります。

ちょっと前に、遅まきながら MT のバージョンを 3.171 から 3.2-ja-2 にアップグレードした。したら、はてなブックマークにブックマークされた際に、記述している記事の概要(excerpt)が反映されなくなった。ちなみに、この <$MTEntryExcerpt$> を反映してくれない件に関しては真琴さん(hxxk.jp)が色々と調べていたんだけど、今んとこ一旦打ち切りという状態になっている。

ここのロジックが内部でどう実装されているかを明示していないのが理由で少々混乱を与えてしまっていて、申し訳ないです。現時点でどういう実装をしているかというのを以下に記載します。(将来的にはきちんとまとめてヘルプあたりに記載したいと思います。)

処理の内容ですが、実は 11月末にちょっと変更を加えました。それまではフィードからの概要取得の際、はてなブックマークを開発した当初やや急いで作った正規表現ゴリゴリな感じでやってたのですが、内部で XML::Feed という Perl のユニバーサル Feed Parser (RSS のどのバージョンでも、Atom でも parse できるやつ) を使うように変更しました。

処理の流れですが、

  1. 該当エントリーに Feed Auto-Discovery を実行する
  2. その中で最初に見つかった Feed (link タグで一番上にあるもの) を GET する
  3. Feed を parse して、ブックマークされた URI を link 要素にもつ要素を探す
  4. その要素に content 部分 (RSS 1.0 なら content:encoded、Atom なら content) があればそれを取得、なければ description を取得

という感じになっています。このいずれかの流れでその取得に失敗した場合は、HTML コンテンツの中からそれっぽい部分を取得する、という感じになっています。

なので、例えば

  • ブックマークされたエントリーに Auto-Discovery のリンクがなかった、そもそもフィードがなかった
  • Well-Formed じゃないなどの何らかの理由で Feed の parse に失敗した
  • content も description もない
  • ブックマークされたエントリーが古いエントリーで、そのサイトが提供しているフィードには掲載されていない
  • ブックマークされたエントリーの Auto-Discovery の最初の結果で見つかるフィードが、そのドキュメントと関連していない
  • フィードの link 要素の URI と、ブックマークされた URI が異なる (FeedBurner などを使っていてリダイレクタが挟まっていたりする場合など)

などの場合に、「それっぽい部分を取得する」という処理に任せることになります。このそれっぽい部分を...という処理はヒューリスティクスで、あまりたいしたことをしていないので、取得に失敗する確率が結構高く、また取得してきた部分が的はずれなことも多いです。

あと、description(概要) よりも content (本文)を優先していますが、どちらを優先するのかがやや微妙なところで、エントリーページの概要として掲載する分には description を採用するのがベストなのですが、キーワードを抽出したり後に検索用にデータをインデックスしたりという場合には content があるならそちらが望ましい、ということで今は content を優先しています。

今はこういった感じの実装になっています。HTML を parse して description に相当するメタデータがあればそれを使う、という手もあるのですが、その場合もやはりキーワードリンクや検索に使えるだけの長さかどうかという話が出てきます。description と content を別々に保存して...と改善する余地はあると思います。

検索やキーワード抽出に使うならなぜはじめから HTML を使わないのか、という点ですが、これははてなブックマークを作るときにみんなと議論して、HTML だけで力業で解決するという選択肢もあるけど、メタデータがあるならそれを利用するのがベターである、という結論に至ったからだったと思います。また、コストも後者の方が低くなります。

長くなってしまいましたが、いまはこういった実装になっています。

そういえば、これを作った当時と、あと今書いていて思ったことがあります。現在のデファクトの実装では Permalink から Auto-Discovery で参照されるフィードには、記事が古かった場合など、その Permalink URI が指し示すドキュメントが含まれていない場合が多く、過去のデータをフィードで参照したいと思ったときにそれができません。

Permalink URI の中にはもう一つ別種類の、そのエントリーだけが格納されているフィードを探す Auto-Discovery な手段があるといいなと思いました。

はてなダイアリーみたいなフルに動的なコンテンツ管理ツールだと実装は結構簡単です。Movable Type のような静的ファイルを作るものも、各エントリーごとにもう一つファイル(フィード)をはき出すようにして、一度全部 Rebuild してやれば ok だと思います。