2011/02/24

.NET用のオープンソースなHTMLのパーサー : Html Agility Pack

かくかくしかじかでHTMLの解析をする必要があったのでけれど、
.NETにはXMLのパーサーはあれどもHTMLのパーサーがないので
なんかいいものがないかと探していたところ、
なかなか良さげなツールを見つけたのでそのメモ。

ちなみに、
System.Windows.Forms.HtmlDocument ってのもあるけれど、
WebBrowserコントロール経由でないとインスタンスを取得できないとか、
InternetExplorerに依存しているとか、
InternetExplorerのバージョンによって影響されるとか、
HTMLの文字列だけほしいのに画像までダウンロードしてくるので遅くて重いとか、
まぁ、もろもろの問題があるので使えない。

で、今回の本題はこっち。
Html Agility Pack
http://htmlagilitypack.codeplex.com/

.NET向けのHTMLパーサーです。
オープンソースでフリーのライブラリ。

使い方について
あんまり情報が見つからなかったので
その辺について。

まずはじめに1つ。
using HtmlAgilityPack;
と書くと、
System.Windows.Forms.HtmlDocument と曖昧な参照になってしまい
コンパイルエラーになるので、
using hap = HtmlAgilityPack;
とかしておいた方がいい。

基本的に、HTMLの解析には、
HtmlAgilityPack.HtmlDocument
というクラスを中心に使用します。

HTMLのソースは、たとえばこんな感じで取得する。
System.Net.WebClient web = new System.Net.WebClient();
string htmlSource = web.DownloadString(url);
ほかにも、ブラウザでソースを表示させてコピペとかいろいろ方法はある。

HtmlAgilityPack.HtmlDocument html = new HtmlAgilityPack.HtmlDocument();
html.LoadHtml( htmlSource; );

これだけで、ソースのロードは完了。

html.Load( url );
で、URLからダウンロードしてくることも出来るっぽい。

あとは、XPathという、XMLの特定の要素を指定したりするための言語を使って
目当ての要素を取得する。
XPathの詳細はgoogle先生に任せるとして、

HtmlAgilityPack.HtmlNodeCollection tags = html.DocumentNode.SelectNodes( xPath );
とすれば、該当するタグのコレクションが取得できる。

XPathは、たとえば、

HtmlAgilityPack.HtmlNodeCollection ulNodes = html.DocumentNode.SelectNodes( "//ul" );
とすれば、ページ内の
<ul> ~</ul>
でくくられた部分を一通り取得する。
さらに、

HtmlAgilityPack.HtmlNodeCollection liNodes = ulNodes[0].SelectNodes( ".//li" );
とすると、最初の<ul></ul>内の
<li></li>要素のコレクションが取得できる。

HtmlAgilityPack.HtmlNode li = html.DocumentNode.SelectSingleNode( "//ul[1]/li[2]" );
で、1つめの<ul></ul>内の
2番目の<li></li>要素を取得したりとか、

HtmlAgilityPack.HtmlNode td = html.DocumentNode.SelectSingleNode( "//table[1]//td[3]" );
で、1つめの<table></table>内に出現する3つめの<td></td>を取得したり。

HtmlAgilityPack.HtmlNode a = html.DocumentNode.SelectSingleNode( "//a[0]" );
string linkUrl = System.Web.HttpUtility.HtmlDecode( a.GetAttributeValue( "href", "" ) );
で、ハイパーリンクのアドレスを取得したりもできる。

逆に、
HtmlNode.XPathプロパティからXPathを取得することもできる。

つまるところ、XPathをうまいこと指定してやることで、
簡単にほしい情報をHTMLから引っこ抜いてこれる。

5 件のコメント:

  1. こんばんわ
    GLSharpのDemoSampleで、プロジェクションモードを変更したところ、cam.ProjectionMode = ProjectionMode.Ortho;
    マウスホイールでのズームができなくなりました。
    this.cam.Zoom( 1f + (e.Delta / 120f * 0.1f) );
    ズームを可能にするには、どうしたらよいでしょうか?

    返信削除
  2. どうも、一歩二歩散歩です。
    マウスホイールでのズームは、注視点とカメラとの距離を変更しています。
    一方、ProjectionMode.OrthoはOpenGLのglOrtho()に対応していますので、正射影なとなり、当然ながら注視点とカメラとの距離を変更しても、透視射影のようなズームにはなりません。
    ProjectionMode.Orthoで視野を変更するには、Camera.orthoHeightを変更し、CAmera.ApplyProjection()を使用してプロジェクション行列を設定し直してください。

    返信削除
  3. こんばんわ
    マウスピッキングの仕方で悩んでいます。gl.Begin(BeginMode.Points);で、任意の点を描画し、その点をヒットして、メッセージボックスに、XYZの座標を表示させたいのですが、List hitObjects=Selection.Pick(this.models,…で、どうしたらオブジェクトとして渡し、値を得ることができるでしょうか?

    返信削除
  4. そのような単純な用途であれば、
    無理に Selection.Pick() を使わずに、
    直接OpenGLのセレクションモードを使って
    コードを書いた方が簡単なような
    気がします。

    参考:
    http://sonson.jp/?p=64
    http://sky.geocities.jp/freakish_osprey/opengl/opengl_selection.htm

    セレクションバッファの解析には、
    GLSharpの
    SelectionData.ParseSelectionBuffer()
    が使えると思います。

    返信削除
  5. こんばんわ
    アドバイスのように、OpenGLのセレクションモードを使ってできるようになりました。
    ありがとうございます。
    Selection.Pick() や、SelectionData.ParseSelectionBuffer()
    基本的な知識不足で使うことができず、残念でした。

    返信削除