コードをカリカリ書く。JavaでHtmlのパース。

この前、面接に行ってきて技術的にやっぱ偏ってんな〜っと思ったので、ちょっと家でコーディング(ま、仕事では使いそうにない技術ですが)。


で、今作っているもの概要。


題して「かしこいハテブ」。


ハテブでもいちいち人のをブックマークを見るのめんどいし、ホットエントリも結構当てにならなかったりするので、自分の趣向に合ったエントリを自動で探してもらおうみたいなコンセプトのアプリです。


で内容。

  1. 自分がブックマークしているエントリのユーザを洗い出す。
  2. 「過去の人気エントリー」をブックマークしているユーザと、自分のブックマークしていたエントリのユーザをマッチングして、自分好みのエントリか判定


で、これを実現するためにハテブで提供しているAPIではデータがたりなかったので、HTMLパースをする羽目に。


で、HTMLパースをすることになったのだが、Javaの標準ライブラリではいいものが余りない。DOMでパースできればよかったんだけど、XMLとしては整形式じゃないで駄目。JavaScriptみたいなことがやりたいだけなのに、ぱっと日本語で情報が入って使いやすそうなものがない、、、


で、結局諦めて、べたべたの「javax.swing.text.html」の辺りを使うことにしました。
ただし、これ、コールバック型でSAXみたいな感じなんで使いにくいんですよね・・・。

例えば、下記のようなHTMLがあった場合、

<a href="http://www.itmedia.co.jp/news/articles/0807/18/news074.html" 
 class="bookmark" target="_blank">
元ドコモの夏野氏、iPhone早速入手 ひろゆき氏は「電話として不便」 
- ITmedia News"</a>

下記のような感じで、「class」で狙い撃ちできれば、簡単に属性のデータを取れるんだけ、地のテキスト(上の例だとアンカーされるテキスト)とるのは結構面倒。

public class HatebuParser extends HTMLEditorKit.ParserCallback {

//フィールドは省略

public void handleStartTag
 (HTML.Tag tag, MutableAttributeSet attr, int pos) {
   if (tag.equals(HTML.Tag.A)
           && "bookmark".equals(
        attr.getAttribute(HTML.Attribute.CLASS))) {

           link = (String) attr.getAttribute(HTML.Attribute.HREF);
           flagTitle = true;

    }
}

public void handleText(char[] data, int pos) {
  if (flagTitle) {
      flagTitle = false;
      title = new String(data);
  }
}
}


実際のコードは、フラグだらけで、このタグ見つけて、で、次にこのタグが来るはずで、、、、フラグ消して、、、とか相当うざいコードになってしまいました。


ただ、もう慣れたし、あと色々作りこんだので当分は上記のクラスベースで行く予定です。


で、実際にできたものの感触はいまいち・・・・・
orz.........
(半分ぐらいは蹴れてるかも。要精査。)


自分好みのエントリっていうのは、自分のブックマーク履歴から吸い上げるんでいいんだろうけど、自分の嫌いなエントリ、興味の無いエントリを吸い上げる方法を取り込んでないっていうのが問題のようです。


いま、やっている方法は、一旦全てのエントリを嫌いとみなして、好きなタイプのエントリで拾い上げるって感じのロジック。
色々チューニングが必要そうです。


今見ているのは、ユーザーと、ドメイン情報しかないんで、タグ情報や、ハテナスター、エントリHTML本文も見たほうがいいのか思案中です。


後、問題なのはロジックが相当重いんで、サービスにはできそうに無いってあたりかな、、、、(1ユーザごとに専用のテーブル持ってるような感じ)。ユーザの傾向抽出をしてグルーピングできればって思うんですけど、このあたりはまだノーアイデアです。本当は、この辺つきつめってってGoogle App Engineとかに乗せたいな〜とか妄想してるんだけど、、、、。


とりあえず、まったり作ります。