如何在Python中使用Xpath?


224

有哪些支持Xpath的库?是否有完整的实现?图书馆如何使用?它的网站在哪里?


4
我暗中怀疑这个问题的答案现在有点陈旧。
沃伦·P

4
@ gringo-suave的答案似乎是一个很好的更新。stackoverflow.com/a/13504511/1450294
Michael Scheper 2013年

Scrapy提供了XPath选择器
cs95

正如@WarrenP所说,这里的大多数答案都是非常陈旧的Python-2.x,真的过时了。也许这个问题应该标记为python-2.x
smci

Answers:


129

libxml2具有许多优点:

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

缺点包括:

  1. 符合规范。严格 在其他库中,诸如默认名称空间处理之类的事情会更容易。
  2. 使用本机代码。这可能会很麻烦,具体取决于您的应用程序的分发/部署方式。可使用RPM来减轻这种痛苦。
  3. 手动资源处理。请注意下面的示例中对freeDoc()和xpathFreeContext()的调用。这不是很Pythonic。

如果您要进行简单的路径选择,请坚持使用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


8
在osx上使用python 2.7.10我必须将ElementTree导入为from xml.etree.ElementTree import ElementTree
Ben Page

因为它是C包装程序,否则除非将其编译到AWS Linux的EC2实例或Docker映像上,否则可能很难将其部署到AWS Lambda
CpILL '18


56

在这里听起来像lxml广告。;)ElementTree包含在std库中。在2.6及以下版本中,它的xpath相当弱,但在2.7+中则大大改善了

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 even in 2.6:
    if elem.attrib.get('name') == 'foo':
        result = elem.text
        break

39

使用LXML。LXML充分利用了libxml2和libxslt的功能,但是将它们包装在比这些库中固有的Python绑定更多的“ Pythonic”绑定中。这样,它将获得完整的XPath 1.0实现。本机ElemenTree支持XPath的有限子集,尽管它可能足以满足您的需求。


29

另一个选项是py-dom-xpath,它可以与minidom无缝协作,并且是纯Python,因此可以在appengine上运行。

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

2
如果您已经在使用minidom,那么它比lxml和libxml2更容易。工作精美,更“ Pythonic”。函数中的contextin find允许您将另一个xpath结果用作新的搜索上下文。

3
在编写插件时,我也一直在使用py-dom-xpath,因为它是纯python。但是我不认为它已得到维护,并且请注意以下错误(“无法访问名称为'text'的元素”):code.google.com/p/py-dom-xpath/issues/detail?id = 8
乔恩·库姆斯

py-dom-xpath似乎已在2010年被封存,请至少将其编辑为您的答案。
smci

14

您可以使用:

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

当我尝试PyXML代码时,我ImportError: No module named ext来自from xml.dom.ext.reader import Sax2
Aminah Nuraini,2015年

9

最新版本的elementtree很好地支持XPath。我不是XPath专家,我不能肯定地说实现是否完整,但是在使用Python时它可以满足我的大多数需求。我也使用了lxml和PyXML,我发现etree很不错,因为它是一个标准模块。

注意:从那以后我就找到了lxml,对我来说,它绝对是Python最好的XML库。它也很好地完成了XPath(尽管可能不是完整的实现)。


7
目前,ElementTree的XPath支持最多为最小。功能上存在巨大的漏洞,例如缺少属性选择器,没有非默认轴,没有子索引等。1.3版(在Alpha中)添加了其中的一些功能,但仍是一个不失所趋的部分实现。
James Brady


7

如果您希望同时拥有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!'

如果我想获得“链接1”和“链接2”,我的Xpath应该如何?
weefwefwqg3

1
为了获取文本,应该是这样的//li/a/text()
eLRuLL


3

PyXML运作良好。

您没有说要使用什么平台,但是如果您使用的是Ubuntu,则可以使用sudo apt-get install python-xml。我敢肯定其他Linux发行版也有。

如果您使用的是Mac,则xpath已安装但无法立即访问。可以PY_USE_XMLPLUS在导入xml.xpath之前在您的环境中进行设置或以Python方式进行设置:

if sys.platform.startswith('darwin'):
    os.environ['PY_USE_XMLPLUS'] = '1'

在最坏的情况下,您可能必须自己构建它。该软件包不再维护,但仍然可以正常运行,并且可以与现代2.x Python一起使用。基本文档在这里


0

如果您需要html

import lxml.html as html
root  = html.fromstring(string)
root.xpath('//meta')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.