Html Agility Pack无法使用xpath找到元素,但它可以与WebDriver一起使用

.net html-agility-pack webdriver xpath

我已经看过这些问题12但不适合我。

我正在为WebDriver正常工作的对象创建Xpath,但是当试图使用HtmlAgilityPack选择节点时,它在某些情况下不起作用。

我正在使用最新的HtmlAgilityPack 1.4.9

例如, 是一个页面。

在此处输入图像描述

以红色突出显示的对象的xpath是

// section [@ id ='main-content'] / div 2 / div / div / div / div / div / p 1 / a

同样,另一个对象如图所示

在此处输入图像描述

这是xpath

// section [@ id ='main-content'] / div 2 / div / div / div / div / div / ul / li 2 / a

这两个Xpath在WebDriver中工作得非常好,但无法从HtmlAgility包中找到任何对象。

对于我试过的第一个

HtmlAgilityPack.HtmlNode.ElementsFlags.Remove( “P”)

它开始工作,但为什么需要它?第二个也没有运气。

是否需要从ElementFlags中删除任何特定标记列表?如果有,那会对它产生什么影响?

我的要求是使用HtmlAgility包中的Xpath获取对象,就像WebDriver一样。

任何帮助将不胜感激。

编辑1:

我们从HAP获得的XPATH也很长,比如div / div / div / div / div / a这里是Sir Simon给出的例子的VB.Net代码

Dim selectedNode As HtmlAgilityPack.HtmlNode = htmlAgilityDoc.DocumentNode.SelectSingleNode("//section[@id='main-content']//div[@class='pane-content']//a")

Dim xpathValue As String = selectedNode.XPath

然后我们从HAP获得的xpathValue是

/ html 1 / body 1 / section 1 / div 2 / div 1 / div 1 / div 1 / div 1 / div 1 / a 1

一般承认的答案

使用XPATH时,WebDriver将始终依赖目标浏览器。从技术上讲,它只是浏览器的一个奇特的桥梁(浏览器是Firefox还是Chrome - IE最多11不支持XPATH)

遗憾的是,驻留在浏览器内存中的DOM(元素和属性结构) 您可能提供给Html Agility Pack的DOM不同。如果从浏览器内存中加载带有DOM内容的HAP(例如,相当于document.OuterHtml),它可能是相同的。通常情况并非如此,因为开发人员使用HAP在没有浏览器的情况下废弃站点,因此他们从网络流(来自HTTP GET请求)或原始文件中提取它。

这个问题很容易证明。例如,如果您创建的文件仅包含以下内容:

<table><tr><td>hello world</td></tr></table>

(没有html,没有body标签,这实际上是一个无效的html文件)

使用HAP,您可以像这样加载它:

HtmlDocument doc = new HtmlDocument();
doc.Load(myFile);

HAP的结构就是这样:

+table
 +tr
  +td
   'hello world'

HAP不是一个浏览器,它是一个解析器,它并不真正了解HTML规范,它只知道如何解析一堆标签并用它构建一个DOM。它不知道例如文档应该以HTML开头,并且应该包含BODY,或者在浏览器推断时TABLE元素始终具有TBODY子元素。

但是在Chrome浏览器中,你打开这个文件,检查它并向XPATH询问TD元素,它会报告这个:

/html/body/table/tbody/tr/td

因为Chrome刚刚自己完成了这个......正如你所看到的那两个系统不匹配。

请注意,如果源HTML中有id属性,则故事情况会更好,例如,使用以下HTML:

<table><tr><td id='hw'>hello world</td></tr></table>

Chrome会报告以下XPATH(它会尝试尽可能多地使用id属性):

//*[@id="hw"]

也可用于HAP。但是,这并不是一直有效。例如,使用以下HTML

<table id='hw'><tr><td>hello world</td></tr></table>

Chrome现在将为TD生成此XPATH:

//*[@id="mytable"]/tbody/tr/td

如你所见,由于推断的TBODY,这在HAP中不再可用。

因此,最后,您不能盲目地在其他上下文中使用浏览器生成的XPATH而不是那些浏览器。在其他情况下,您必须找到其他歧视。

实际上,我个人认为它在某种程度上是一件好事,因为它会让你的XPATH更能抵抗变化。但你必须考虑:-)

现在让我们回到你的案例:)

以下C#示例控制台案例应该可以正常工作:

  static void Main(string[] args)
  {
      var web = new HtmlWeb();
      var doc = web.Load("http://www2.epa.gov/languages/traditional-chinese");
      var node = doc.DocumentNode.SelectSingleNode("//section[@id='main-content']//div[@class='pane-content']//a");
      Console.WriteLine(node.OuterHtml); // displays <a href="http://www.oehha.ca.gov/fish/pdf/59329_CHINESE.pdf">...etc...</a>"
  }

如果您查看流或文件的结构(甚至浏览器显示的内容,但要小心,避免TBODY ...),最简单的方法是

  • 找到一个id (就像浏览器一样)和/或
  • 以递归或非递归的方式在此下面找到唯一的子元素或大子元素或属性
  • 避免过于精确的XPATH。像p/p/p/div/a/div/whatever都不好

所以,在这里,在main-content id属性之后,我们只是(递归地用// )查找具有特殊类的DIV,然后我们看(再次递归)第一个子A可用。

这个XPATH应该在webdriver和HAP中工作。

注意这个XPATH也有效: //div[@class='pane-content']//a但它看起来有点宽松。设置id属性的脚通常是一个好主意。




许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因