Html Agility Pack - 选择子节点时出现问题

30

我想将我的 Asics 跑步计划导出到 iCal,但由于 Asics 不提供此服务,所以我决定为自己构建一个小型爬虫。我的目标是从计划中获取所有安排好的跑步并基于此生成一个 iCal 订阅源。我正在使用 C# 和 Html Agility Pack。

我想要做的是遍历我所有预定的跑步(它们都是 div 节点)。然后我想选择一些不同的节点与我的跑步节点一起使用。我的代码看起来像这样:

foreach (var run in doc.DocumentNode.SelectSingleNode("//div[@id='scheduleTable']").SelectNodes("//div[@class='pTdBox']"))
{
    number++;
    string date = run.SelectSingleNode("//div[@class='date']").InnerText;
    string type = run.SelectSingleNode("//span[@class='menu']").InnerHtml;
    string distance = run.SelectSingleNode("//span[@class='distance']").InnerHtml;
    string description = run.SelectSingleNode("//div[@class='description']").InnerHtml;
    ViewData["result"] += "Dato: " + date + "<br />";
    ViewData["result"] += "Tyep: " + type + "<br />";
    ViewData["result"] += "Distance: " + distance + "<br />";
    ViewData["result"] += "Description: " + description + "<br />";
    ViewData["result"] += run.InnerHtml.Replace("<", "&lt;").Replace(">", "&gt;") + "<br />" + "<br />" + "<br />";
}
我的问题是run.SelectSingleNode("//div[@class='date']").InnerText不能在给定的运行节点中选择具有给定XPath的节点。它会选择整个文档中与XPath匹配的第一个节点。
如何在当前节点中选择具有给定XPath的单个节点?
谢谢。
更新:
我尝试将我的XPath字符串更新为:
string date = run.SelectSingleNode(".div[@class='date']").InnerText;
这应该选择当前节点内的<div class="date"></div>元素,对吧?好的,我尝试过这样做,但是出现了以下错误:

表达式必须评估为节点集。说明:在执行当前 Web 请求的过程中发生未处理的异常。请查看堆栈跟踪以获取有关错误和代码起源的更多信息。

异常详细信息:System.Xml.XPath.XPathException: 表达式必须评估为节点集。

有什么建议吗?

我在XPath方面并不是很熟练,但是//不是表示从根节点的任何地方吗? - Alxandr
似乎你需要类似于 child::div[@class='data'] 的东西,但我并不确定。完全不确定。 - Alxandr
2个回答

63
一些在使用 HtmlAgilityPackXPath 表达式时有帮助的事情。
如果 run 是一个 HtmlNode,则:
  1. run.SelectNodes("//div[@class='date']")
    会像 doc.DocumentNode.SelectNodes("//div[@class='date']") 一样工作。

  2. run.SelectNodes("./div[@class='date']")
    将给你所有的是 <div> 节点,它们是 run 节点的子节点。它不会搜索更深的层次,只会在下一个深度级别上进行。

  3. run.SelectNodes(".//div[@class='date']")
    将返回该类属性的所有 <div> 节点,但不仅限于紧接着 run 节点旁边的节点,而且还会在深度上搜索(每个可能的后代)。

你需要根据自己的需求选择 2. 或 3.。

3
哇,你真的救了我的命。我刚刚搞不清1和3。谢谢啊兄弟。 - Soren
3
我也遇到了同样的情况 :) - Oscar Mederos

3
在XPATH中,//表示当前节点以下的所有子代和后代。因此,您需要提供更具限制性的XPATH表达式。如果您提供真实的HTML以及您确切需要什么,我们可以帮助您进一步了解。
关于您遇到的错误: .div[@class='date']是无效的,因为.div连接在一起。您可以使用div[@class='date']./div[@class='date'],我相信它们是等效的。这是因为.是一个XPATH轴,它是alias forself,表示“当前节点”。

@Simon Mourier - 我也在尝试从一个具有属性“name”的节点获取数据,但它没有接受它。 - Zameer Ansari
1
@学生 - 你应该写另一个问题。 - Simon Mourier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接