python - 使用 python ElementTree 内存不足

标签 python xml elementtree

编辑:将来任何人都会遇到这个问题,我使用的解决方案是切换到 cElementTree。它不仅运行时内存更少,而且速度明显更快。

这适用于大小最大约为 600mb 的文件,大于此值并且我的内存不足(我有一台 16GB 的机器)。我可以做些什么来分块读取文件,或者一次读取一定比例的 xml,或者是否有内存密集程度较低的方法?

import csv
import xml.etree.ElementTree as ET
from lxml import etree
import time
import sys

def main(argv):
    start_time = time.time()

#file_name = 'sample.xml'
file_name = argv
root = ET.ElementTree(file=file_name).getroot() 
csv_file_name = '.'.join(file_name.split('.')[:-1]) + ".txt"
print '\n'
print 'Output file:'
print csv_file_name

with open(csv_file_name, 'w') as file_:
    writer = csv.writer(file_, delimiter="\t")
    header = [ <the names of the tags here> ]
    writer.writerow(header)
    tags = [
        <bunch of xml tags here>    
            ]

    #write the values
#     for index in range(8,1000):
    for index in range(3,len(root)):
        #print index
        row=[]
        for tagindex,val in enumerate(tags):
            searchQuery = "tags"+tags[tagindex]
#             print searchQuery
#             print root[index]
#             print root[index].find(searchQuery).text
            if (root[index].find(searchQuery) is None) or (root[index].find(searchQuery).text == None):
                row.extend([""])
                #print tags[tagindex]+" blank"
            else:
                row.extend([root[index].find(searchQuery).text])
                #print tags[tagindex]+" "+root[index].find(searchQuery).text
        writer.writerow(row)


    #for i,child in enumerate(root):
        #print root[i]
    print '\nNumber of elements is: %s' % len(root)

print '\nTotal run time: %s seconds' % (time.time() - start_time)

if __name__ == "__main__":
    main(sys.argv[1])

最佳答案

一些提示:

  • 使用lxml,性能非常好
  • 使用iterparse,它可以逐段处理您的文档

但是,iterparse 可能会让您感到惊讶,并且您最终可能会消耗大量内存。为了克服这个麻烦,您必须清除对已处理项目的引用,如我最喜欢的关于 effective lxml usage 的文章中所述。

使用优化的 iterparse 的示例脚本 fastiterparse.py

安装docoptlxml

$ pip install lxml docopt

编写脚本:

"""For all elements with given tag prints value of selected attribute
Usage:
    fastiterparse.py <xmlfile> <tag> <attname>
    fastiterparse.py -h
"""
from lxml import etree
from functools import partial

def fast_iter(context, func):
    for event, elem in context:
        func(elem)
        elem.clear()
        while elem.getprevious() is not None:
            del elem.getparent()[0]
    del context

def printattname(elem, attname):
    print elem.attrib[attname]

def main(fname, tag, attname):

    fun = partial(printattname, attname=attname)
    with open(fname) as f:
        context = etree.iterparse(f, events=("end",), tag=tag)
        fast_iter(context, fun)

if __name__ == "__main__":
    from docopt import docopt
    args = docopt(__doc__)
    main(args["<xmlfile>"], args["<tag>"], args["<attname>"])

尝试调用它:

$ python fastiterparse.py                                               
Usage:
    fastiterparse.py <xmlfile> <tag> <attname>
    fastiterparse.py -h

使用它(在您的文件上):

$ python fastiterparse.py large.xml ElaboratedRecord id
rec26872
rec25887
rec26873
rec26874

结论(使用fast_iter方法)

主要要点是 fast_iter 函数(或者至少记住清除未使用的元素,删除它们,最后删除上下文

测量结果表明,在某些情况下,在没有 cleardel 的情况下,脚本运行速度稍慢,但差异并不显着。优点是目前内存有限,因为当它开始交换时,优化版本会变得更快,并且如果内存不足,没有太多其他选择。

关于python - 使用 python ElementTree 内存不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24126299/

相关文章:

python - 使用 xml.etree.ElementTree 更改 xml 元素文本

Python xml解析etree按位置查找元素X

python - 使用 elementtree 获取和更新 xml 中的值

执行大型案例/切换的 Pythonic 方式

python - _raise_connection_failure 中的 AutoReconnectpymongo.pool

python - 即使以前导入过,Cufflinks 如何将方法注入(inject) Pandas?

python - 使用 ElementTree 将 xml 转换为字典

python - csv导入sqlite3而不指定列类型

java - 如何忽略 JaxB 中元素名称的大小写

javascript - xml 添加属性转义 &