编辑:将来任何人都会遇到这个问题,我使用的解决方案是切换到 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
安装docopt
和lxml
$ 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
函数(或者至少记住清除
未使用的元素,删除它们,最后删除上下文
测量结果表明,在某些情况下,在没有 clear
和 del
的情况下,脚本运行速度稍慢,但差异并不显着。优点是目前内存有限,因为当它开始交换时,优化版本会变得更快,并且如果内存不足,没有太多其他选择。
关于python - 使用 python ElementTree 内存不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24126299/