lxml' iterparse尝试将整个文件加载到内存中

时间:2014-05-03 10:10:41

标签: python lxml

我正在尝试解析一个非常庞大的XML文件,因此我决定使用lxml.iterparse,如here所述。

所以我的代码看起来像这样:

import sys
from lxml import etree

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 launchArticleProcessing(elem):
    print elem

context = etree.iterparse(sys.argv[1], events=('end',), tag='text')

fast_iter(context, launchArticleProcessing)

我这样说:python lxmlwtf.py "/path/to/my/file.xml"

内存刚刚填满(直到我杀死进程,因为文件永远不适合它)并且没有任何内容被打印出来。我在这里缺少什么?

3 个答案:

答案 0 :(得分:2)

我在这里回答了一个非常类似的问题:lxml and fast_iter eating all the memory主要原因是因为lxml.etree仍然在内存中保留了未明确捕获的所有元素。因此,您需要手动清除。

我所做的不是过滤您正在寻找的标签的事件:

context = etree.iterparse(open(filename,'r'),events=('end',))

而是手动解析并清除其余部分:

for (event,elem) in progress.bar(context):
    if elem.tag == 'text':
        # do things here

    # every element gets cleared here
    elem.clear()
    while elem.getprevious() is not None:
        del elem.getparent()[0]
del context

答案 1 :(得分:1)

我的不好,正如我的评论中所解释的那样。 lxml将文件加载到内存中,直到找到与给定标记对应的项目。

如果找不到标记(例如因为lxml会将命名空间添加到它中),它只会无限期地将文件加载到内存中,因此会出现问题。

所以修复是提供正确的标签!我在我的文件子集上使用常规解析器找到了正确的解析器。

答案 2 :(得分:0)

根据我的经验,定期调用垃圾收集器可能会有所帮助。

这样的事情可以解决问题:

import sys
from lxml import etree

def fast_iter(context, func):
    for i, (event, elem) in enumerate(context):
        # Garbage collect after every 100 elements
        if i % 100 == 0:
            gc.collect()

        func(elem)
        elem.clear()
        while elem.getprevious() is not None:
            del elem.getparent()[0]
    del context

def launchArticleProcessing(elem):
    print elem

context = etree.iterparse(sys.argv[1], events=('end',), tag='text')

fast_iter(context, launchArticleProcessing)