尝试在 c# 中使用 xpath select 光滑的 href 属性

Trying to select slippery href attribute with xpath in c#

试图从站点抓取 .pdf,但 XPath 很顽固。

Site I'm trying to get the .pdf from

检查给出的 xpath > 复制 > 复制 xpath:

//*[@id="content"]/div/table[2]/tbody/tr[0]/td[3]/a

出于某种原因,/tbody 除了引发问题外什么也没做。删除它对我正在使用的所有其他 Xpath 都有效,而且似乎也是去这里的方法。

//*[@id="content"]/div/table[2]/tr[0]/td[3]/a

这会产生结果:

<img width="16" height="16" src="/apps/cba/g_doctype_pdf.gif" border="0"><br><small>Download<br>Agreement</small>

哪个似乎是 child 节点?

在任何情况下都支持 xpath 到:

//*[@id="content"]/div/table[2]/tr[0]/td[3]

让我明白

<a target="_blank" href="/apps/cba/docs/1088-CBA6-2017_Redacted.pdf"><img width="16" height="16" src="/apps/cba/g_doctype_pdf.gif" border="0"><br><small>Download<br>Agreement</small></a>

这很好,因为我只需要 href 属性中的值,我可以重建 URL 等等。我不是 XPath 的向导,但在我看来,这个最后的调整应该让我得到我想要的东西:

//*[@id="content"]/div/table[2]/tr[0]/td[3]/@href

不过它又 returns 了标签。 我对此感到难过。有什么建议吗?

编辑:

标记的解决方案让我明白我是在做一个假设。我假设我可以像取消引用其他 节点 一样取消引用 href 标签。事实并非如此,我不得不将取消引用调整为如下所示:

var node_collection = hdoc.DocumentNode.SelectNodes(@"//*[@id=""content""]/div/table[2]/tr[1]/td[3]/a/@href");
string output = node[0].Attributes["href"].Value

问题根本不在 Xpath 上。问题是我对我正在处理的 HtmlDocument object 缺乏理解。粘贴我试图获取 href 标签的位置会让任何有经验的人都明白这一点。对 copy-pasting 我的整个混乱代码块过于自我意识使得任何人都无法帮助我。孩子们,从我的错误中吸取教训,健壮的代码段更容易准确地识别问题。

你说得对,tbody 是由 Chromes 在复制 XPath 上添加的,应该删除,因为它不存在于原始 HTML 代码中。 *

选择 href 属性应按建议工作://*[@id="content"]/div/table[2]/tr[1]/td[3]/a/@href

我可以像这样加载第一个 href:

HtmlWeb web = new HtmlWeb();
HtmlDocument hdoc = web.Load("https://work.alberta.ca/apps/cba/searchresults.asp?query=&employer=&union=&locality=&local=&effective_fy=&effective_fm=&effective_ty=&effective_tm=&expiry_fy=&expiry_fm=&expiry_ty=&expiry_tm=");

var nav = (HtmlNodeNavigator)hdoc.CreateNavigator();
var val = nav.SelectSingleNode(@"//*[@id=""content""]/div/table[2]/tr[1]/td[3]/a/@href").Value;

或者所有人都这样:

XPathNavigator nav2 = hdoc.CreateNavigator();
XPathNodeIterator xiter = nav2.Select(@"//*[@id=""content""]/div/table[2]/tr/td[3]/a/@href");
while (xiter.MoveNext())
{
    Console.WriteLine(xiter.Current.Value);
}

* 但是,某些引擎确实要求 tbody 出现在 XPath 中,正如 here. Only then we get a result. See this answer 为什么 Chrome 添加了 tbody, Firebug,和第一个一样。