【问题标题】:Trying to select slippery href attribute with xpath in c#尝试在 c# 中使用 xpath 选择滑的 href 属性
【发布时间】:2019-05-22 22:12:07
【问题描述】:

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

Site I'm trying to get the .pdf from

inspect 给出的 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>

哪个似乎是子节点?

在任何情况下,将 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

但是它再次返回标签。 我被这件事难住了。有什么建议吗?

编辑:

标记的解决方案让我明白我在做一个假设。我假设我可以以与取消引用其他 节点 相同的方式取消引用 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 对象缺乏了解。粘贴我试图获取 href 标记的地方会让任何有经验的人都明白这一点。过于自觉地复制粘贴我的整个凌乱代码块使得任何人都无法帮助我。孩子们,从我的错误中吸取教训,健壮的代码部分可以更轻松地准确识别问题。

【问题讨论】:

  • //*[@id="content"]/div/table[2]/tr[0]/td[3]/@href 将给出None,因为td 没有href 属性。当您尝试使用//*[@id="content"]/div/table[2]/tr[0]/td[3]/a/@href 时,您应该看到href,它不是显示href 值吗?
  • 不,它返回 标签。就好像@href 部分甚至不存在一样。
  • 嗯。你的工具集是什么?
  • 在某些 XPath 引擎中,您应该使用特定于属性的方法来获取属性值,例如:GetAttribute() 而不是 GetNode()
  • 我正在使用 c# 和 HtmlAgilityPack

标签: c# xpath html-agility-pack


【解决方案1】:

你说得对,tbody 是 Chrome 在 Copy 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 所示。只有这样我们才能得到结果。请参阅 this answer 为什么首先由 Chrome、Firebug 等添加 tbody

【讨论】:

  • 我想当然地认为我可以使用 Xpath 直接索引到 hdoc 中的任何信息。这适用于我拉下的所有其他字段,但是要访问此 href 属性需要我正确取消引用节点。我将尝试编辑问题以使其有用。
猜你喜欢
  • 2016-06-27
  • 1970-01-01
  • 1970-01-01
  • 2013-07-09
  • 2014-12-09
  • 1970-01-01
  • 2017-08-11
  • 2016-12-28
  • 1970-01-01
相关资源
最近更新 更多