首页 文章

HtmlAgilityPack并选择节点和子节点

提问于
浏览
33

希望有人可以帮助我 .

假设我有一个包含多个div的html文档,如下例所示:

<div class="search_hit">

    <span prop="name">Richard Winchester</span>
    <span prop="company">Kodak</span>
    <span prop="street">Arlington Road 1</span>

</div>
<div class="search_hit">

    <span prop="name">Ted Mosby</span>
    <span prop="company">HP</span>
    <span prop="street">Arlington Road 2</span>

</div>

我正在使用HtmlAgilityPack来获取html文档 . 我需要知道的是我如何获得每个“search_hit”-div的 Span ?

我的第一个想法是这样的:

foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
     foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("//span[@prop]"))
     {

     }
}

每个div应该是包含spans作为属性的对象 . I. e .

public class Record
    {
        public string Name { get; set; }
        public string company { get; set; }
        public string street { get; set; }
    }

然后填写此清单:

public List<Record> Results = new List<Record>();

但我正在使用的XPATH并没有在子节点中进行搜索,因为它应该这样做 . 它接缝一遍又一遍地搜索整个文档 .

我的意思是我已经让它以这种方式工作,我只是得到整个页面的 Span . 但后来我在 Span 和div之间没有任何关系 . 意思是:我不知道哪个 Span 与哪个div有关 .

有人知道解决方案吗?我已经玩了很多,我现在完全糊涂了:)

任何帮助表示赞赏!

5 回答

  • 2

    以下适用于我 . 重要的是就像BeniBela注意到在第二次调用'SelectNodes'时添加一个点 .

    List<Record> lstRecords=new List<Record>();
    foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
    {
      Record record=new Record();
      foreach (HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
      {
        string attributeValue = node2.GetAttributeValue("prop", "");
        if (attributeValue == "name")
        {
          record.Name = node2.InnerText;
        }
        else if (attributeValue == "company")
        {
          record.company = node2.InnerText;
        }
        else if (attributeValue == "street")
        {
          record.street = node2.InnerText;
        }
      }
      lstRecords.Add(record);
    }
    
  • 30

    如果您使用 // ,则从文档开始搜索 .

    使用 .// 从当前节点搜索所有内容

    foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
    

    或者完全删除前缀以搜索直接子项:

    foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("span[@prop]"))
    
  • 47

    首先,看看这个: Html Agility Pack - Problem selecting subnode

    以下是针对您的问题的完整解决方案:

    IList<Record> results = new List<Record>();
    foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
        var record = new Record();
        record.Name = node.SelectSingleNode(".//span[@prop='name']").InnerText;
        record.company = node.SelectSingleNode(".//span[@prop='company']").InnerText;
        record.street = node.SelectSingleNode(".//span[@prop='street']").InnerText;
        results.Add(record);
    }
    

    如果您阅读我指出的问题,您将看到执行 ./span[@prop='name'] 完全相同,因为那些 span 节点是 div 节点的(直接)子节点 .


    如果 span 节点没有那些 prop 属性,并且您希望根据它们出现的顺序分配它们,则可以执行以下操作:

    foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
        var spanNodes = node.SelectNodes("./span");
        var record = new Record();
        record.Name = spanNodes[0].InnerText;
        record.company = spanNodes[1].InnerText;
        record.street = spanNodes[2].InnerText;
        results.Add(record);
    }
    
  • 2

    我很遗憾:)

    你们所有人都是对的 .

    我发现了这个问题 . 这个NullReferenceException一直在唠叨我,所以我花了更多的时间详细研究它 . 在所有这些div之间有一个div具有相同的“class ='search-hit'”属性但没有内部的 Span . 这就是为什么它在第二个循环中通过错误的原因 .

    foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//span[@prop]/ancestor::div[@class='search_hit']"))
       {
            Record rec = new Record();
            foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
               {
               }
               rList.Results.Add(rec);
       }
    

    上面的代码正在运行 .

    谢谢你们的时间和帮助!

  • 0

    我用过它 . class convert id

    HtmlNodeCollection nodes = dokuman.DocumentNode.SelectNodes("//div[@id='search_hit']//span[@prop]");
    
    
                for (int i = 0; i < nodes .Count; i++)
            {
                var record = new Record();
    
    
                    record.Name = links[i].InnerText;   results.Add(record);  }
    

相关问题