【问题标题】:Html Agility Pack cannot find element using xpath but it is working fine with WebDriverHtml Agility Pack 无法使用 xpath 找到元素,但它与 WebDriver 一起工作正常
【发布时间】:2015-08-31 21:29:03
【问题描述】:

我已经看到这些问题12 但对我不起作用。

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

我正在使用最新的 HtmlAgilityPack 1.4.9

例如,Here 是一个页面。

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

//section[@id='main-content']/div2/div/div/div/div/div/p1/a

如图所示的另一个对象

它的xpath是

//section[@id='main-content']/div2/div/div/div/div/div/ul/li2/a

这两个 Xpath 在 WebDriver 中都可以正常工作,但无法从 HtmlAgility 包中找到任何对象。

我第一次尝试

HtmlAgilityPack.HtmlNode.ElementsFlags.Remove("p")

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

是否有需要从 ElementFlags 中删除的特定标签列表?如果有,那么它的影响是什么?

我的要求是使用 Xpath 从 HtmlAgility 包中获取对象,就像 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就是

/html1/body1/section1/div2/div1/div1/div1/div1/div1/a 1

【问题讨论】:

    标签: .net xpath webdriver html-agility-pack


    【解决方案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"]
    

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

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

    Chrome 现在将生成此 XPATH 到 TD:

    //*[@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 属性通常是个好主意。

    【讨论】:

    • 感谢西蒙的回答。您指出像 'p/p/p/div/a/div/whatever' 这样的 XPATH 不好,为什么 HAP 本身要创建这样的 XPATH? Here 是我目前用来创建 XPATH 的链接。
    • HAP 没有创建任何 XPATH。 mshtml 是 Internet Explorer 对象模型
    • 不,我是说我们从 HtmlAgilityPack.HtmlNode 得到的 XPATH。假设您给出的上述示例我们正在选择 HtmlNode,然后查看它的 XPATH。使用 VB.Net 代码更新问题以从 HAP 获取 XPATH。
    • 哦。我以前从未评论过这一点(我很久以前创作了 HAP - 有人已将这个功能添加到 HAP)。好吧,它应该比浏览器更好,因为它将使用 HAP DOM,但是,我总是更喜欢精心设计的 XPATH :-)
    • 作为快速修复将 html 传递给 Tidy.Net,然后在 HAP 中使用它帮助我更多地选择节点。对于永久修复,我知道我需要通过避免过于精确的 XPATH 和松散的属性(如 p、tbody 等)来构建一些新的逻辑来生成 XPATH。感谢西蒙爵士的帮助。
    猜你喜欢
    • 2011-09-01
    • 2011-04-14
    • 2019-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    • 1970-01-01
    相关资源
    最近更新 更多