如何在Python中使用XPath?

257

哪些库支持XPath?是否有完整的实现?该库如何使用?它的网站在哪里?


6
我有一种隐隐的猜想,认为这个问题的答案现在有点过时了。 - Warren P
4
@gringo-suave的回答看起来是一个不错的更新。https://dev59.com/X3VD5IYBdhLWcg3wWKPc#13504511 - Michael Scheper
Scrapy提供XPath选择器 - cs95
正如@WarrenP所说,这里的大多数答案都是极其陈旧的Python-2.x,真的很过时。也许这个问题应该被标记为[tag:python-2.x]。 - smci
11个回答

136

libxml2具有以下优点:

  1. 符合规范
  2. 积极的开发和社区参与
  3. 速度快。这实际上是一个围绕C实现的Python包装器。
  4. 普及性。libxml2库是无处不在的,因此经过了充分测试。

缺点包括:

  1. 符合规范。它很严格。默认命名空间处理等问题在其他库中更容易。
  2. 使用本地代码。根据应用程序的分发/部署方式,这可能会带来麻烦。提供了一些RPM可以缓解这种痛苦。
  3. 手动资源处理。请注意下面示例中调用freeDoc()和xpathFreeContext()。这不太符合Python风格。

如果您只需要进行简单的路径选择,请使用ElementTree(已包含在Python 2.5中)。如果您需要完全符合规范或原始速度,并且能够处理本地代码的分发,那么请使用libxml2。

libxml2 XPath使用示例


import libxml2

doc = libxml2.parseFile("tst.xml")
ctxt = doc.xpathNewContext()
res = ctxt.xpathEval("//*")
if len(res) != 2:
    print "xpath query: wrong node set size"
    sys.exit(1)
if res[0].name != "doc" or res[1].name != "foo":
    print "xpath query: wrong node set value"
    sys.exit(1)
doc.freeDoc()
ctxt.xpathFreeContext()

ElementTree XPath使用示例


from elementtree.ElementTree import ElementTree
mydoc = ElementTree(file='tst.xml')
for e in mydoc.findall('/foo/bar'):
    print e.get('title').text


9
在 OSX 上使用 Python 2.7.10,我不得不将 ElementTree 导入为 from xml.etree.ElementTree import ElementTree - Ben Page
因为它是一个C语言封装,所以你可能会发现在AWS Lambda上部署它有困难,除非你在EC2实例或AWS Linux的Docker镜像上进行编译。 - CpILL
严格性不是缺点。 - Dragas
libxml2 不是 Python 的内置模块,对吧?如果要使用内置的 xml 库,应该怎么做呢? - Eric Dand

86

lxml包支持xpath。 尽管我在self::轴上遇到了一些问题,但它似乎运行良好。 还有Amara,但我个人尚未使用过。


1
Amara很不错,而且并不总是需要使用xpath。 - gatoatigrado
3
请添加一些关于如何使用lxml和XPath的基本细节。 - jpmc26
有一个标准库的解决方案。我更喜欢少依赖。请参考Gringo Suave的答案。 - Ted Shaneyfelt

79
听起来像是在这里做一个lxml的广告 ;) ElementTree已经包含在标准库中。在2.6及以下版本中,它的xpath功能相对较弱,但在2.7+和3.x版本中得到了很大的改进
import xml.etree.ElementTree as ET

root = ET.parse(filename)
result = ''

for elem in root.findall('.//child/grandchild'):
    # How to make decisions based on attributes:
    if elem.attrib.get('name') == 'foo':
        result = elem.text
        break

40

使用LXML。 LXML充分利用libxml2和libxslt的强大功能,并将它们包装在比那些库本地Python绑定更“Pythonic”的绑定中。因此,它获得了完整的XPath 1.0实现。原生的ElemenTree支持XPath的有限子集,虽然它可能已经足够满足您的需求。


32

另一个选择是py-dom-xpath,它可以与minidom无缝配合,并且是纯Python编写的,因此可以在appengine上运行。

import xpath
xpath.find('//item', doc)

3
如果你已经在使用minidom,那么它比lxml和libxml2更易于使用。它的表现很好,而且更符合“Pythonic”的风格。find函数中的context参数允许你将另一个xpath结果作为新的搜索上下文使用。 - Ben
5
我也一直在使用py-dom-xpath,因为它是纯Python的,非常适合写插件。但我认为它已经不再维护了,要注意这个错误(“无法访问名为'text'的元素”):https://code.google.com/p/py-dom-xpath/issues/detail?id=8 - Jon Coombs
3
据悉,py-dom-xpath 似乎早在2010年就已经被搁置了(https://code.google.com/archive/p/py-dom-xpath/),请务必将此信息至少编辑到您的答案中。 - smci

15

你可以使用:

PyXML:

from xml.dom.ext.reader import Sax2
from xml import xpath
doc = Sax2.FromXmlFile('foo.xml').documentElement
for url in xpath.Evaluate('//@Url', doc):
  print url.value

libxml2

import libxml2
doc = libxml2.parseFile('foo.xml')
for url in doc.xpathEval('//@Url'):
  print url.content

1
当我尝试运行PyXML代码时,我从from xml.dom.ext.reader import Sax2得到了ImportError: No module named ext的错误提示。 - Aminah Nuraini

11

您可以使用 soupparser 来自 lxml

示例:

from lxml.html.soupparser import fromstring

tree = fromstring("<a>Find me!</a>")
print tree.xpath("//a/text()")

使用 soupparser 会有什么不同? - Padraic Cunningham
这只是一个替代方案。 - Aminah Nuraini

9
如果你想结合XPATH的强大功能,并且在任何时候也能使用CSS,那么你可以使用parsel
>>> from parsel import Selector
>>> sel = Selector(text=u"""<html>
        <body>
            <h1>Hello, Parsel!</h1>
            <ul>
                <li><a href="http://example.com">Link 1</a></li>
                <li><a href="http://scrapy.org">Link 2</a></li>
            </ul
        </body>
        </html>""")
>>>
>>> sel.css('h1::text').extract_first()
'Hello, Parsel!'
>>> sel.xpath('//h1/text()').extract_first()
'Hello, Parsel!'

如果我想获取“Link 1”和“Link 2”,我的Xpath应该是什么样子? - weefwefwqg3
1
获取文本的代码应该类似于 //li/a/text() - eLRuLL

9

elementtree的最新版本支持XPath非常好。虽然我不是XPath专家,但我可以肯定地说,它的实现已经满足了我在Python中工作时的大部分需求。我还使用过lxml和PyXML,但我发现etree很好,因为它是一个标准模块。

注意:我后来发现lxml,对我来说,它绝对是Python中最好的XML库。它也很好地支持XPath(虽然可能没有完全实现)。


7
ElementTree的XPath支持目前最多只能算是基本水平。功能上存在着巨大的漏洞,例如缺乏属性选择器、没有非默认轴、没有子元素索引等等。版本1.3(处于alpha测试阶段)增加了其中的一些功能,但仍然是一个毫不掩饰的部分实现。 - James Brady

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接