HtmlAgilityPack,然后选择Nodes和Subnodes
本文关键字:Subnodes Nodes 选择 然后 HtmlAgilityPack | 更新日期: 2023-09-27 18:00:27
希望有人能帮我。
假设我有一个包含多个divs
的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
的跨度?
我的第一个想法是这样的:
foreach (HtmlAgilityPack.HtmlNode node in
doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("//span[@prop]"))
{
}
}
每个div
都应该是一个以包含的跨度为属性的对象:
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
并没有像它应该做的那样在子节点中进行搜索。它一次又一次地搜索整个文档。
我的意思是,我已经用这种方式工作了,我只得到了整个页面的跨度,但spans
和divs
之间没有关系。意思是,我不再知道哪个span
和哪个div
有关。
有人知道解决方案吗?我已经玩了那么多,现在我完全困惑了
感谢您的帮助!
如果使用//
,它将从文档开始搜索。
使用.//
从当前节点中搜索所有
foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
或者完全去掉前缀,只搜索直接子代:
foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("span[@prop]"))
以下内容适用于我。重要的一点正如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);
}
首先,看看这个:Html敏捷包-选择子节点的问题
以下是您的问题的完整工作解决方案:
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);
}
我真丢脸:)
你们都是对的。
我发现了问题。这个NullReferenceException一直困扰着我,所以我花了更多的时间来详细研究它。在所有这些div之间,有一个div具有相同的"class=‘search-hit’"属性,但内部没有跨度。这就是它在第二个循环中出错的原因。
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);
}
上面的代码正在工作。
谢谢你们的时间和帮助!
我用过这个。类转换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); }