2011年2月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 件のコメント:

匿名 さんのコメント...

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

一歩二歩散歩 さんのコメント...

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

匿名 さんのコメント...

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

一歩二歩散歩 さんのコメント...

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

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

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

匿名 さんのコメント...

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