HtmlAgilityPackの基本
HTMLからスクレイピングでデータを抜き出す際に使用しました。
現時点でわかった使用例を示します。
HTML code example
<html> <head></head> <body> <h3>企業いろいろ</h3> <h4>コンビニ</h4> <ul> <li><a href="711.htm">セブン-イレブン</a></li> <li><a href="lawson.htm">ローソン</a></li> <li><a href="famima.htm">ファミリーマート</a></li> </ul> <h4>PC</h4> <ul> <li class="usa"><a href="hp.htm">HP</a></li> <li class="usa"><a href="dell.htm">Dell</a></li> <li><a href="epson.htm">Epson Direct</a></li> </ul> <h4>EC</h4> <ul> <li class="usa"><a href="amazon.htm">Amazon</a></li> <li><a href="rakuten.htm">楽天</a></li> </ul> <div class="migi">注意:順不同です</div> <div id="footer">copyright 2013 Kobarin</div> </body> </html>
前処理(対象によって変更して下さい)
string html = ""; //HTMLコード HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument(); doc.OptionAutoCloseOnEnd = false; //最後に自動で閉じる(?) doc.OptionCheckSyntax = false; //文法チェック。 doc.OptionFixNestedTags = true; //閉じタグが欠如している場合の処理 doc.LoadHtml(html);
取得コード
Exp1. id・classを指定しての要素を取得(単一取得)
HtmlAgilityPack.HtmlNode node1 = doc.DocumentNode.SelectSingleNode("div[@id='footer']"); Console.WriteLine(node1.InnerHtml);
結果
copyright 2013 Kobarin
Exp2. <li>タグの中身を全部取得
HtmlAgilityPack.HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//li"); foreach(HtmlAgilityPack.HtmlNode node in nodes){ Console.WriteLine(node.InnerHtml); }
結果
<a href="711.htm">セブン-イレブン</a> <a href="lawson.htm">ローソン</a> <a href="famima.htm">ファミリーマート</a> <a href="hp.htm">HP</a> <a href="dell.htm">Dell</a> <a href="epson.htm">Epson Direct</a> <a href="amazon.htm">Amazon</a> <a href="rakuten.htm">楽天</a> <a href="yahoo.htm">ヤフーショッピング</a>
Exp3. aタグの文字列部分を取得
HtmlAgilityPack.HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//a"); foreach(HtmlAgilityPack.HtmlNode node in nodes){ Console.WriteLine(node.InnerHtml); }
結果
セブン-イレブン ローソン ファミリーマート HP Dell Epson Direct Amazon 楽天 ヤフーショッピング
Exp4. 特定classのタグのみ取得
//<li class="usa">のタグを取得 HtmlAgilityPack.HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//li[@class='usa']"); foreach(HtmlAgilityPack.HtmlNode node in nodes){ Console.WriteLine(node.InnerHtml); }
結果
<a href="hp.htm">HP</a> <a href="dell.htm">Dell</a> <a href="amazon.htm">Amazon</a>
Exp5. 順番を指定して特定タグを取得
//body直下にある、2番目のdivタグ HtmlAgilityPack.HtmlNode node = doc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[2]"); Console.WriteLine(node.InnerHtml);
結果
copyright 2013 Kobarin
Exp6. aタグのhref内のURLを全て取得
HtmlAgilityPack.HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//a"); foreach (HtmlAgilityPack.HtmlNode node in nodes) { string url = node.GetAttributeValue("href", ""); Console.WriteLine(url); }
結果
711.htm lawson.htm famima.htm hp.htm dell.htm epson.htm amazon.htm rakuten.htm yahoo.htm
Exp7. 全ul内の1番目のli内のリンク文字列だけ取得
HtmlAgilityPack.HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//li[1]/a"); foreach(HtmlAgilityPack.HtmlNode node in nodes){ Console.WriteLine(node.InnerHtml); }
結果
セブン-イレブン HP Amazon
Exp8. 全ul内の最後のli内のリンク文字列を取得
HtmlAgilityPack.HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//li[last()]/a"); foreach(HtmlAgilityPack.HtmlNode node in nodes){ Console.WriteLine(node.InnerHtml); }
結果
ファミリーマート Epson Direct 楽天
Exp9. 各ul内で2番目以降にあり、且つclassが"usa"のli内にあるリンク文字列を取得
HtmlAgilityPack.HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//li[position() >= 2 and contains(@class, 'usa')]/a"); foreach(HtmlAgilityPack.HtmlNode node in nodes){ Console.WriteLine(node.InnerHtml); }
結果
Dell
Exp10. a内のテキストに'D'を含む内容を取得(※カンマを使います)
HtmlAgilityPack.HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//a[contains(.,'D')]"); foreach(HtmlAgilityPack.HtmlNode node in nodes){ Console.WriteLine(node.InnerHtml); }
結果
Dell Epson Direct
注意点
HTMLコードそのものにエラーがあると正常に処理されません。
例えば私が試した所では、閉じタグが抜けていたり、<div><p></div></p>のように互い違いになっていると抽出も出来ないため、ソースコードの段階で補正をしてやる必要があります。
参考
HtmlAgilityPackの記述は原則的にXPathに準拠するらしく、自分の場合はXPath Syntaxを参考にさせて頂きました。
また、HtmlAgilityPack Simulatorも公開しましたので、記述テスト等にお使い下さい。