【问题标题】:lxml bug in .xpath?.xpath 中的 lxml 错误?
【发布时间】:2012-03-19 02:44:13
【问题描述】:

在浏览了用于 python 的 lxml 教程中的 xpath 之后,我发现很难理解 2 种对我来说似乎是错误的行为。首先,即使我的 xpath 表达式清楚地只选择了一个元素,lxml 似乎也会返回一个列表,其次,.xpath 似乎返回元素的父元素,而不是直接通过 xpath 搜索表达式选择的元素本身。

是我对 XPath 的理解全错了还是 lxml 确实有 bug?

复制我正在谈论的行为的脚本:

from lxml.html.soupparser import fromstring
doc = fromstring("""
    <html>
        <head></head>
        <body>
            <p>Paragraph 1</p>
            <p>Paragraph 2</p>
        </body>
    </html>
""")

print doc.xpath("//html")
#[<Element html at 1f385e0>]
#(This makes sense - return a list of all possible matches for html)

print doc.xpath("//html[1]")
#[<Element html at 1f385e0>]
#(This doesn't make sense - why do I get a list when there
#can clearly only be 1 element returned?)   

print doc.xpath("body")
#[<Element body at 1d003e8>]
#(This doesn't make sense - according to
#http://www.w3schools.com/xpath/xpath_syntax.asp if I use a tag name
#without any leading / I should get the *child* nodes of the named
#node, which in this case would mean I get a list of
#p tags [<Element p at ...>, <Element p at ...>]

【问题讨论】:

    标签: python xpath lxml


    【解决方案1】:

    这是因为doc的上下文节点是'html'节点。当您使用doc.xpath('body') 时,它会选择'html' 的子元素'body'。这符合XPath 1.0 standard

    【讨论】:

    • 值得一提的是doc.xpath() 总是返回一个列表。它简化了使用.xpath() 的代码。一般来说,总是返回确认相同协议的对象(在这种情况下是一系列元素)是一个好主意。
    【解决方案2】:

    所有p标签都应该是doc.findall(".//p")

    根据指南,表达式nodename 选择命名节点的所有子节点。 因此,要仅使用节点名(不带 /),您必须选择一个命名节点(要选择父节点作为命名节点,请使用点)。

    【讨论】:

    • 我的问题不在于我无法弄清楚如何使用 lxml 来选择所有 p 标签。我的问题是找出为什么 lxml 没有错误,因为它的行为与我根据 XPath 教程所期望的不同
    【解决方案3】:

    事实上,doc.xpath("//html[1]") 可以返回多个节点,其输入文档与您的示例不同。该路径选择第一个匹配 //html 的兄弟。如果有匹配的非兄弟元素,它将选择每个元素的第一个兄弟。
    XPath:(//html)[1] 强制执行不同的求值顺序。它选择文档中的所有匹配元素,然后选择第一个。

    但是,无论如何,始终返回一个列表是一种更好的 API 设计。否则,代码将始终必须在处理列表之前测试单个值或 None 值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-17
      • 2012-09-29
      • 2011-07-17
      • 2016-03-06
      • 1970-01-01
      相关资源
      最近更新 更多