我正在为WebDriver工作正常的对象创建Xpath,但是当尝试使用HtmlAgilityPack选择节点时,它在某些情况下无效。
我正在使用最新的HtmlAgilityPack 1.4.9
例如,Here是一个页面。
以红色突出显示的对象的xpath是
//部[@id ='主内容'] / DIV 2 / DIV / DIV / DIV / DIV / DIV / P 1 / A
同样是另一个对象,如图所示
它的xpath是
//部[@id =&#39;主内容&#39;] / DIV 2 / DIV / DIV / DIV / DIV / DIV / UL /利2 / A < / p>
这些Xpath在WebDriver中工作得非常好,但无法从HtmlAgility包中找到任何对象。
对于我试过的第一个
HtmlAgilityPack.HtmlNode.ElementsFlags.Remove(&#34; P&#34)
它开始起作用,但为什么需要它? 第二个也没有运气。
是否需要从ElementFlags中删除任何特定标记列表?如果有的话会产生什么影响?
我的要求是使用HtmlAgility包中的Xpath获取对象,就像WebDriver一样。
非常感谢任何帮助。
编辑1:
我们从HAP获得的XPATH也很长,比如div / div / div / div / div / a 这是西蒙爵士提供的示例的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是
答案 0 :(得分:3)
使用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
(就像浏览器一样)和/或p/p/p/div/a/div/whatever
这样的事情很糟糕所以,在这里,在main-content
id
属性之后,我们只是(递归地使用//
)查找具有特殊类的DIV,然后我们查看(再次递归)第一个孩子A
可用。
这个XPATH应该可以在webdriver和HAP中使用。
请注意,这个XPATH也有效://div[@class='pane-content']//a
但它看起来有点松散。设置id
属性的脚通常是一个好主意。