2011年2月12日土曜日

HTMLパーサ「Html Agility Pack」を使ってみた

「ブログの本文だけを抜き出したい。」と思い、
"ブログスクレイプ"というツールを作成しました。

その時に
"Html Agility Pack"というHTMLパーサ(HTML解析ツール)を使ったので、
ノウハウをまとめておきたいと思います。

"Html Agility Pack"については、
以下のサイトを参考にさせて戴きました。ありがとうございます。

Html Agility Pack公式サイト

・マイコミジャーナルさん
.NET向けHTMLパーサー「Html Agility Pack」で簡単スクレイピング

・neue ccさん
C#でスクレイピング:HTMLパース(Linq to Html)のためのSGMLReader利用法


開発環境は以下の通りです。
・Microsoft Visual C# 2005 Express Edition
・Windows Vista Ultimate SP2


以下、コードの説明をしていきます。
※ブログ用にコードを編集しているので、おかしな箇所があるかもしれません。。


1.URLを直接"Html Agility Pack"に渡しても良いのですが、
文字コードによって文字化けしてしまうので、
文字化け対策としてStreamReaderを使用して、 
文字コード(EUC)を使用してHTMLを取得しています。
(文字化け対策)

//Uriクラスに格納
String strUri = this.txtUrl.Text;
System.Uri uri = new System.Uri ( strUri );

//Webサイトに接続してHTMLを取得
System.Net.WebClient web = new System.Net.WebClient();

//指定の文字コードでHTMLを取得する
Stream st = web.OpenRead( uri.AbsoluteUri );
StreamReader sr = new StreamReader( st, Encodeing.GetEncoding( 51932 ));
String html = sr.ReadToEnd();
sr.Close();
st.Close();


2."Html Agility Pack"を使います。
1.で取得したhtmlを"Html Agility Pack"に渡します。

//HtmlDocumentクラスにHTMLをセット
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml( html );


3.XPathを使ってコレクションを抽出します。
keywordは、
tableタグのclass要素がcontents_tableである要素を抽出するという意味。

//キーワードを設定する
String keyword = @"//table[@class=""contents_table""]";

//XPathを使ってコレクションを抽出
HtmlNodeCollection body =
doc.DocumentNode.SelectNodes( keyword );


4.取得したノードをforeachで出力しています。
どのノードからHTMLを取得するかによって、
node.OuterHtml、node.InnerHtmlなどを使い分けます。

//コレクションから値を取り出す
StringBuilder strTemp = new StringBuilder();
foreach( HtmlNode node in body )
{
strTemp.Append( node.OuterHtml );
}


5.取得したHTMLをファイルに出力します。
ここではStreamWriterを使用して、文字コード(EUC)を指定しています。
(文字化け対策)

//ファイルに書き込む
StreamWriter sw = new StreamWriter ( stream, Encodeing.GetEncoding( 51932 ));
sw.Write( strTemp.ToString() );
sw.Close();


大切なのは、
・手順3でどのコードを抜き出すか
・手順4でどのノードを出力するか
・文字化け対策
だと思います。


もっと簡単に実現できる方法があるかと思いますが、
参考程度にしていただけると助かります。


blogram投票ボタン

1 件のコメント:

  1. 参考になりました。
    1にEncodingのスペルミスがありますので、一応・・・。

    返信削除