web-dev-qa-db-ja.com

HTML Agility Pack-テーブルの解析

HTMLアジリティパックを使用して複雑なWebページのテーブルを解析したいのですが、オブジェクトモデルではど​​ういうわけか失われます。

リンクの例を見てみましたが、この方法ではテーブルデータが見つかりませんでした。 XPathを使用してテーブルを取得できますか?テーブルの取得方法に関するデータをロードした後、基本的に失われます。これは以前にPerlで行ったことがあり、少し不器用でしたが、うまくいきました。 (HTML::TableParser)。

また、構文解析のための正しいオブジェクトの順序に光を当てることができれば幸いです。

52
weismat

次のようなものはどうですか:使用 HTML Agility Pack

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(@"<html><body><p><table id=""foo""><tr><th>hello</th></tr><tr><td>world</td></tr></table></body></html>");
foreach (HtmlNode table in doc.DocumentNode.SelectNodes("//table")) {
    Console.WriteLine("Found: " + table.Id);
    foreach (HtmlNode row in table.SelectNodes("tr")) {
        Console.WriteLine("row");
        foreach (HtmlNode cell in row.SelectNodes("th|td")) {
            Console.WriteLine("cell: " + cell.InnerText);
        }
    }
}

必要に応じて、LINQ-to-Objectsでよりきれいにできることに注意してください。

var query = from table in doc.DocumentNode.SelectNodes("//table").Cast<HtmlNode>()
            from row in table.SelectNodes("tr").Cast<HtmlNode>()
            from cell in row.SelectNodes("th|td").Cast<HtmlNode>()
            select new {Table = table.Id, CellText = cell.InnerText};

foreach(var cell in query) {
    Console.WriteLine("{0}: {1}", cell.Table, cell.CellText);
}
114
Marc Gravell

特定の要素のXPathを取得するために見つけた最も簡単なことは、FireBugのFireBug拡張機能をインストールすることです。F12キーを押してサイト/ウェブページに移動し、firebugを起動します。クエリするページ上の要素を右クリックして[要素の検査]を選択します。FirebugはIDEで要素を選択し、Firebugの要素を右クリックして[XPathのコピー]を選択しますこの関数は、HTML Agility Libraryを使用して必要な要素を取得するために必要な正確なXPathクエリを提供します。

31
Coda

これはかなり古い質問ですが、これはテーブルを視覚化してクラス構造を作成できるようにした私の解決策でした。これもHTML Agility Packを使用しています

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(@"<html><body><p><table id=""foo""><tr><th>hello</th></tr><tr><td>world</td></tr></table></body></html>");
var table = doc.DocumentNode.SelectSingleNode("//table");
var tableRows = table.SelectNodes("tr");
var columns = tableRows[0].SelectNodes("th/text()");
for (int i = 1; i < tableRows.Count; i++)
{
    for (int e = 0; e < columns.Count; e++)
    {
        var value = tableRows[i].SelectSingleNode($"td[{e + 1}]");
        Console.Write(columns[e].InnerText + ":" + value.InnerText);
    }
Console.WriteLine();
}
2
B. Miller

私の場合、たまたまルータからのデバイスリストである単一のテーブルがあります。上記のマトリックスの代わりにTR/TH/TD(行、ヘッダー、データ)を使用してテーブルを読み取りたい場合、次のようなことができます。

    List<TableRow> deviceTable = (from table in document.DocumentNode.SelectNodes(XPathQueries.SELECT_TABLE)
                                       from row in table?.SelectNodes(HtmlBody.TR)
                                       let rows = row.SelectSingleNode(HtmlBody.TR)
                                       where row.FirstChild.OriginalName != null && row.FirstChild.OriginalName.Equals(HtmlBody.T_HEADER)
                                       select new TableRow
                                       {
                                           Header = row.SelectSingleNode(HtmlBody.T_HEADER)?.InnerText,
                                           Data = row.SelectSingleNode(HtmlBody.T_DATA)?.InnerText}).ToList();
                                       }  

TableRowは、ヘッダーとデータをプロパティとして持つ単純なオブジェクトです。アプローチはnull-nessとこの場合を処理します:

<tr>
    <td width="28%">&nbsp;</td>
</tr>

これはヘッダーのない行です。定数がぶら下がっているHtmlBodyオブジェクトはおそらく容易に推測されますが、それでもなお謝罪します。私は、コードに "が含まれている場合、定数またはローカライズ可能にする必要がある世界から来ました。

1
Shibumi Tait