【问题标题】:Html Agility Pack loop through table rows and columnsHtml Agility Pack 循环遍历表的行和列
【发布时间】:2013-02-04 19:08:46
【问题描述】:

我有一张这样的桌子

<table border="0" cellpadding="0" cellspacing="0" id="table2">
    <tr>
        <th>Name
        </th>
        <th>Age
        </th>
    </tr>
        <tr>
        <td>Mario
        </td>
        <th>Age: 78
        </td>
    </tr>
            <tr>
        <td>Jane
        </td>
        <td>Age: 67
        </td>
    </tr>
            <tr>
        <td>James
        </td>
        <th>Age: 92
        </td>
    </tr>
</table>

并且想使用 HTML Agility Pack 来解析它。我试过这段代码无济于事:

foreach (HtmlNode row in doc.DocumentNode.SelectNodes("//table[@id='table2']//tr"))
{
    foreach (HtmlNode col in row.SelectNodes("//td"))
    { 
        Response.Write(col.InnerText); 
    }
}

我做错了什么?

【问题讨论】:

  • 你能描述一下什么不起作用吗?
  • 我得到一个无限循环
  • 它对我有用(嗯,不完全是,我得到的名字 Mario/Jane/James 重复了 4 次)。请注意,'//td' 不仅仅从当前节点中选择(如您所料)而是从 DocumentNode 中选择。您使用的是哪个版本的 HtmlAgilityPack?
  • 嗯,看起来像您的 .NET 版本。您是否通过 NuGet 获得了 HtmlAgilityPack?
  • 你是对的这是版本:1.4.6.0

标签: c# .net html-agility-pack


【解决方案1】:

你为什么不直接选择tds?

foreach (HtmlNode col in doc.DocumentNode.SelectNodes("//table[@id='table2']//tr//td"))
    Response.Write(col.InnerText);

或者,如果您确实需要将 trs 单独用于其他处理,请删除 // 并执行以下操作:

foreach (HtmlNode row in doc.DocumentNode.SelectNodes("//table[@id='table2']//tr"))
    foreach (HtmlNode col in row.SelectNodes("td"))
        Response.Write(col.InnerText);

当然,这只有在 tds 是 trs 的直接子代时才有效,但它们应该是,对吧?


编辑:

var cols = doc.DocumentNode.SelectNodes("//table[@id='table2']//tr//td");
for (int ii = 0; ii < cols.Count; ii=ii+2)
{
    string name = cols[ii].InnerText.Trim();
    int age = int.Parse(cols[ii+1].InnerText.Split(' ')[1]);
}

使用 LINQ 可能有更令人印象深刻的方法。

【讨论】:

  • 是的,我想使用每一列进行处理,因为您可以看到第二列是数字和文本的混合,我想提取数字。尝试此代码后,页面只是循环,没有结果。
【解决方案2】:

我运行了代码,它只显示 Names,这是正确的,因为 Ages 是使用无效的 HTML 定义的:&lt;th&gt;&lt;/td&gt;(可能是错字)。

顺便说一句,代码可以简化为只有一个循环:

foreach (var cell in doc.DocumentNode.SelectNodes("//table[@id='table2']/tr/td"))
{
    Response.Write(cell.InnerText);
}

这是我用来测试的代码:http://pastebin.com/euzhUAAh

【讨论】:

    【解决方案3】:

    我必须提供完整的 xpath。我从@Coda (https://stackoverflow.com/a/3104048/1238850) 的建议中使用 Firebug 获得了完整的 xpath,我最终得到了以下代码:

    foreach (HtmlNode row in doc.DocumentNode.SelectNodes("/html/body/table/tbody/tr/td/table[@id='table2']/tbody/tr"))
    {
        HtmlNodeCollection cells = row.SelectNodes("td");
        for (int i = 0; i < cells.Count; ++i)
        {
            if (i == 0)
            { Response.Write("Person Name : " + cells[i].InnerText + "<br>"); }
            else {
                Response.Write("Other attributes are: " + cells[i].InnerText + "<br>"); 
            }
        }
    }
    

    我确信它可以写得比这更好,但它现在对我有用。

    【讨论】:

      【解决方案4】:

      我用这个做了同样的项目:

              private List<PhrasalVerb> ExtractVerbsFromMainPage(string content)
          {
              var verbs =new List<PhrasalVerb>(); ;
              HtmlDocument doc = new HtmlDocument();
              doc.LoadHtml(content);
              var rows = doc.DocumentNode.SelectNodes("//table[@class='idioms-table']//tr");
              rows.RemoveAt(0); //remove header
              foreach (var row in rows)
              {
                  var cols = row.SelectNodes("td");
                  verbs.Add(new PhrasalVerb { 
                  Uid = Guid.NewGuid(),
                  Name = cols[0].InnerHtml,
                  Definition = cols[1].InnerText,
                  Count =int.TryParse(cols[2].InnerText,out _) == true ? Convert.ToInt32(cols[2].InnerText) : 0
                  });
              }
              return verbs;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-04-14
        • 2016-06-28
        • 1970-01-01
        • 1970-01-01
        • 2012-12-24
        • 1970-01-01
        相关资源
        最近更新 更多