使用 HtmlAgilitypack 问题解析表

Posted

技术标签:

【中文标题】使用 HtmlAgilitypack 问题解析表【英文标题】:Parse table with HtmlAgilitypack issue 【发布时间】:2015-03-31 21:14:31 【问题描述】:

我正在尝试解析一个如下所示的表:

<table><tbody>
<tr><th a href=""></th><th></th></tr>
<tr><td class="v"></td><td class="d"></td><td class="h"></td><td class="a">   </td><td class="o"></td><td class="o"></td><td class="o"></td><td class="p"><table class="p" title="ttt"></table></td></tr>
<tr><td class="v"></td><td class="d"></td><td class="h"></td><td class="a">   </td><td class="o"></td><td class="o"></td><td class="o"></td><td class="p"><table class="p" title="eee"></table></td></tr>
<tr><td class="v"></td><td class="d"></td><td class="h"></td><td class="a">   </td><td class="o"></td><td class="o"></td><td class="o"></td><td class="p"><table class="p" title="rtr"></table></td></tr>
<tr><th a href=""></th><th></th></tr>
<tr><td class="v"></td><td class="d"></td><td class="h"></td><td class="a">   </td><td class="o"></td><td class="o"></td><td class="o"></td><td class="p"><table class="p" title="ouu"></table></td></tr>
<tr><td class="v"></td><td class="d"></td><td class="h"></td><td class="a">   </td><td class="o"></td><td class="o"></td><td class="o"></td><td class="p"><table class="p" title="teee"></table></td></tr>
</tbody></table>

我在 ASP.net 中使用此代码来获取我想要的每一行中的单元格:

var gethtmlWeb = new HtmlWeb();
var document = getHtmlWeb.Load(txtbox.Text); 
//get tables
foreach (HtmlNode table in document.DocumentNode.SelectNodes("//table"))
        
            //get each table row
            foreach (HtmlNode row in table.SelectNodes("tr"))
            

                Outputlabel.Text += "row: <br />";
//get table head tags that have a link, get the Inner text
                if((row.SelectSingleNode("//th//a").InnerText) != null)
                

                    Outputlabel.Text += row.SelectSingleNode("//th//a").InnerText + "<br />";
                
                // get the cells with the classes I want
                    string d = row.SelectSingleNode("//td[@class='d']").InnerText;
                    Outputlabel.Text += row.SelectSingleNode("//td[@class='d']").InnerText + " ";

                    string h = row.SelectSingleNode("//td[@class='h']").InnerText;
                    Outputlabel.Text += row.SelectSingleNode("//td[@class='h']").InnerText + " ";
                    string a = row.SelectSingleNode("//td[@class='a']").InnerText;
                    Outputlabel.Text += row.SelectSingleNode("//td[@class='a']").InnerText + " ";
                    string op = "";
//there are 3 classes in each row to have the class="o"
                    if (row.SelectNodes("//td[@class='o']") != null)
                    
                        foreach (HtmlNode o in row.SelectNodes("//td[@class='o']"))
                        
                            op += o.InnerText;
                        
                        Outputlabel.Text += op + " ";
                    

                    var pr = row.SelectSingleNode("//td//table[@class='p']");
                    string pr = probability.Attributes["title"].Value;

                    Outputlabel.Text += pr + "<br />";
            
          

我只得到第一个表的第一行,它被重复了很多次......而且我没有得到类“o”和类“p”中的类“p”表的标题p"

【问题讨论】:

检查我的答案,如果对你有帮助,请告诉我。 【参考方案1】:

对于在线的 html 文件似乎是这样工作的:

    HtmlWeb getHtmlWeb = new HtmlWeb();

        HtmlDocument doc = getHtmlWeb.Load(txtbox.Text);

        string d = "//td[@class='d']";
        string h = "//td[@class='h']";
        string a = "//td[@class='a']";
        string p = "//table[@class='p']";


        HtmlNodeCollection ds = doc.DocumentNode.SelectNodes(d);
        HtmlNodeCollection hs = doc.DocumentNode.SelectNodes(h);
        HtmlNodeCollection as = doc.DocumentNode.SelectNodes(a);
        HtmlNodeCollection ps = doc.DocumentNode.SelectNodes(p);
foreach (HtmlNode n in ds)
        
            Outputlabel.Text += n.InnerHtml + "<br />"; 
        

        foreach (HtmlNode h in hs)
        
            Outputlabel.Text += h.InnerHtml + "<br />";
        
        foreach (HtmlNode a in as)
        
            Outputlabel.Text += a.Attributes["href"].Value + "<br />";
        
        foreach (HtmlNode p in ps)
        
            Outputlabel.Text += p.Attributes["title"].Value + "<br />";
        

【讨论】:

只要列的行数相同,我稍后将它们放入二维表中... 我还没有获得“o”类,但我会找到解决方案,也许将列放在一个大小比其他列表大 3 倍的列表中。 将确切的 Html 放入问题中,我将使其也适用于“在线 html”,【参考方案2】:
        public static void Main(string[] args)
        
            string html = @"<!DOCTYPE html>
<html>
<body>


<table>
   <tbody>
      <tr>
         <th a href="""">a</th>
         <th>d2</th>
      </tr>
      <tr>
         <td class=""v"">b</td>
         <td class=""d"">v</td>
         <td class=""h"">g</td>
         <td class=""a"">  d </td>
         <td class=""o"">e</td>
         <td class=""o"">j</td>
         <td class=""o"">z</td>
         <td class=""p"">
            <table class=""p"" title=""ttt""></table>
         </td>
      </tr>
      <tr>
         <td class=""v"">1</td>
         <td class=""d"">2</td>
         <td class=""h"">3</td>
         <td class=""a""> 4  </td>
         <td class=""o"">5</td>
         <td class=""o"">6</td>
         <td class=""o"">7</td>
         <td class=""p"">
            <table class=""p"" title=""eee""></table>
         </td>
      </tr>
      <tr>
         <td class=""v"">a1</td>
         <td class=""d"">b2</td>
         <td class=""h"">v3</td>
         <td class=""a"">  d4 </td>
         <td class=""o"">e5</td>
         <td class=""o"">j6</td>
         <td class=""o"">z7</td>
         <td class=""p"">
            <table class=""p"" title=""rtr""></table>
         </td>
      </tr>
      <tr>
         <th a href="""">23</th>
         <th>qaaa</th>
      </tr>
      <tr>
         <td class=""v"">az</td>
         <td class=""d"">b2</td>
         <td class=""h"">a b</td>
         <td class=""a""> aaaa  </td>
         <td class=""o"">aa</td>
         <td class=""o"">a</td>
         <td class=""o"">aaa</td>
         <td class=""p"">
            <table class=""p"" title=""ouu""></table>
         </td>
      </tr>
      <tr>
         <td class=""v"">z</td>
         <td class=""d"">zz</td>
         <td class=""h"">zzz</td>
         <td class=""a""> zzzz  </td>
         <td class=""o"">zzzzzz</td>
         <td class=""o"">zzzzz</td>
         <td class=""o"">zzzzzzz</td>
         <td class=""p"">
            <table class=""p"" title=""teee""></table>
         </td>
      </tr>
   </tbody>
</table></body>
</html>";

            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(html);


            var coll = doc.DocumentNode.Descendants().Where(x => x.Name == "th" || 
                (x.Name == "td" && 
                    (x.Attributes["class"].Value == "v" || 
                     x.Attributes["class"].Value == "d" ||
                     x.Attributes["class"].Value == "h" ||
                     x.Attributes["class"].Value == "a" ||
                     x.Attributes["class"].Value == "o")) ||
                (x.Name=="table" && x.Attributes["class"] != null &&  x.Attributes["class"].Value == "p")).ToList();

            foreach (HtmlNode node in coll)
            
                if(node.Name=="table")
                
                    Console.WriteLine(node.Attributes["title"].Value);
                
                else
                
                    Console.WriteLine(node.InnerText.Trim());
                
              
        

您应该采用特定元素而不是整个表格。这是获取所有th,td InnerText 并返回table 的标题和class="p" 的代码。

今后也请格式化您的 HTML!

这是您的逻辑的关键部分。我没有选择td class="p",因为您只从该元素中获取表格标题

var coll = doc.DocumentNode.Descendants().Where(x => x.Name == "th" || 
                (x.Name == "td" && 
                    (x.Attributes["class"].Value == "v" || 
                     x.Attributes["class"].Value == "d" ||
                     x.Attributes["class"].Value == "h" ||
                     x.Attributes["class"].Value == "a" ||
                     x.Attributes["class"].Value == "o")) ||
                (x.Name=="table" && x.Attributes["class"] != null &&  x.Attributes["class"].Value == "p")).ToList();

【讨论】:

当 HTML 代码像示例中一样时它可以工作,但是当我尝试解析在线网站的代码时它不起作用......可能是我使用的 HtmlWeb 方法下载了它但是然后它无法使用 doc.LoadHtml() 方法正确加载... 您正在展示一个示例代码,我正在使用它。下次显示正确的 html ...

以上是关于使用 HtmlAgilitypack 问题解析表的主要内容,如果未能解决你的问题,请参考以下文章

使用 HtmlAgilityPack 解析 HTML 页面

如何使用 htmlagilitypack 解析这个 HTML 文本?

HTML 解析类库HtmlAgilityPack

HtmlAgilityPack XPath 错误

C# HTML解析工具HtmlAgilityPack使用实例

HTML 敏捷包 - 解析表