【问题标题】:Python - Fastest way to find elements in XML documentsPython - 在 XML 文档中查找元素的最快方法
【发布时间】:2015-09-03 18:59:11
【问题描述】:

我需要搜索大约 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

【问题讨论】:

  • 有多慢才是真正的慢,你希望它走多快?
  • 标签和你的例子一样简单吗?如果他们只是&lt;something&gt;this is the text you want&lt;/something&gt;,我会推荐一个正则表达式。
  • @Thecheater887 哦,无论如何它并不慢。在过去的 75 分钟内,我浏览了大约 200 万份文档。我只是怀疑有更快的方法,如果是这样的话,我想加快这家伙的速度,只是知道如何更好地处理这种情况。
  • @porglezomp 标签具有属性,但这在正则表达式中肯定是更易于管理的。你认为这会比 xml 库更快?
  • 非常感谢您的检查,@Thecheater887。仅供参考,走正则表达式路线会带来巨大的速度提升。我的意思是令人震惊的速度提升。

标签: python xml


【解决方案1】:

在 lxml 文档中找到了一些基准 (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

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

【讨论】:

    【解决方案2】:

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

    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 解析器的完整解析,您应该会看到显着的加速。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-22
      • 1970-01-01
      • 2011-04-01
      相关资源
      最近更新 更多