Python - 在XML文档中查找元素的最快方法

时间:2015-09-03 18:59:12

标签: python xml

我需要搜索~10M小(5-10K)XML文档以获取两个标签的文本内容。标签并不总是出现在树中的相同位置,也不总是出现在文档中。

只是为了澄清,如果我有这样的文件:

<a>
  <b>
    <c>
      hello
    </c>
    <d>
      goodbye
    </d>
  </b>
  <e>
    <c>
      howdy
    </c>
    <g>
      nope
    </g>
  </e>
</a>
<d>
  salutations
</d>

我需要从c和d标签中提取文本信息,我会得到

hello goodbye howdy salutations

我目前正在使用xml.etree.ElementTree.findall('.//c'),但它的运行速度非常慢。有没有更快的方法来找到这些标签?我应该使用XML解析库吗?

我正在使用Python 2.7和xml.etree.ElementTree

2 个答案:

答案 0 :(得分:1)

在lxml docs(http://lxml.de/performance.html

中找到了一些基准测试

树遍历

XML处理的另一个重要领域是树遍历的迭代。如果您的算法可以从XML树的逐步遍历中受益,特别是如果感兴趣的元素很少或目标元素标记名称已知,则.iter()方法是一个不错的选择:

lxe: iter_all             (--TR T1)    1.0529 msec/pass
cET: iter_all             (--TR T1)    0.2635 msec/pass

lxe: iter_islice          (--TR T2)    0.0110 msec/pass
cET: iter_islice          (--TR T2)    0.0050 msec/pass

lxe: iter_tag             (--TR T2)    0.0079 msec/pass
cET: iter_tag             (--TR T2)    0.0112 msec/pass

lxe: iter_tag_all         (--TR T2)    0.1822 msec/pass
cET: iter_tag_all         (--TR T2)    0.5343 msec/pass

这直接转换为Element.findall()的相似时间:

lxe: findall              (--TR T2)    1.7176 msec/pass
cET: findall              (--TR T2)    0.9973 msec/pass

lxe: findall              (--TR T3)    0.3967 msec/pass
cET: findall              (--TR T3)    0.2525 msec/pass

lxe: findall_tag          (--TR T2)    0.2258 msec/pass
cET: findall_tag          (--TR T2)    0.5770 msec/pass

lxe: findall_tag          (--TR T3)    0.1085 msec/pass
cET: findall_tag          (--TR T3)    0.1919 msec/pass

请注意,除了原生树迭代器(element.iter())之外,所有三个库当前对.findall()使用相同的Python实现。通常,lxml对于迭代来说非常快,但是当找到许多元素并且需要实例化时,它会对cET失去作用。因此,您的搜索选择性越强,lxml的运行速度就越快。

答案 1 :(得分:1)

根据评论的声音,您有两个非常具体的标签。无需解析整个文件。

import re
pattern = re.compile(r'<[c|d][^>]*>(?P<text>[^<]*)</[c|d]>')
with open('filename', 'r') as f:
    for txt in pattern.finditer(f.read()):
        print(txt.group('text').strip())

使用已编译的正则表达式并避免完全解析xml解析器,您应该会看到显着的加速。