lxml iterparse填充内存,尽管清楚

时间:2014-10-17 21:46:55

标签: python xml parsing lxml iterparse

我正在尝试解析xml。首先iterparse工作正常,但第二次开始填充内存。如果删除第一个iterparse,则没有任何变化。 Xml有效。

def clear_element(e):
    e.clear()
    while e.getprevious() is not None:
        del e.getparent()[0]

def import_xml(request):
    f = 'file.xml'
    offers = etree.iterparse(f, events=('end',), tag='offer')
    for event, offer in offers:
        # processing
        # works correctly
        clear_element(offer)

    categories = etree.iterparse(f, events=('end',), tag='category')
    for event, category in categories:
        # using memory
        clear_element(category)

XML:

<shop>
    <categories>
        <category>name</category>
        <category>name</category>
        <category>name</category>
          ~ 1000 categories
    </categories>
    <offers>
        <offer>
           <inner_tag>data</inner_tag>
           <inner_tag>data</inner_tag>
        </offer>
        <offer>
           <inner_tag>data</inner_tag>
           <inner_tag>data</inner_tag>
        </offer>
          ~ 450000 offers
    </offers>
</shop>

2 个答案:

答案 0 :(得分:3)

您首次解析文件两次,第一次保留所有category代码并删除offer代码,而category代码不是category代码留下那么多记忆。

但是第二次只删除offer标记,同时保留所有450000 tag标记,这就是构建树需要大量内存的原因。

在这种情况下,最好不要将iterparse参数用于def import_xml(request): f = 'file.xml' elements = etree.iterparse(f, events=('end',)) for event, element in elements: if element.tag == 'offer': # handle offer ... elif element.tag == 'category': # handle category ... else: continue element.clear() element.getparent().remove(element) 并检查标记名,同时删除所有不需要的标记:

element.clear()

注意:只是调用clear而不从父项中删除它仍然会将已清除的元素作为构造树的一部分留在内存中。可能{{1}}真的不需要......

答案 1 :(得分:0)

我和iterparse的战斗已经有一段时间了,现在终于认为我知道如何正确使用它,所以这里有我的智慧之词: 使用iterparse时:

  1. 请务必使用cElementTree实施

  2. 确保清除在此过程中不需要的任何元素。如果您的XML具有深层嵌套结构,那么这一点尤为重要。

  3. 因此,我们假设您的XML有这样的其他节点:

    <offers>
        <offer>
           <inner_tag>data</inner_tag>
                  <i2>
                        <i3>1000 characters of something</i3>                       
                 </i2>
           <inner_tag>data</inner_tag>
        </offer>
    </offers>
    

    那么你的代码应该是这样的:

    def import_xml(request):
    f = 'file.xml'
    elements = etree.iterparse(f, events=('end',))
    for event, element in elements:
        if element.tag == 'offer':
            # handle offer ...
        elif element.tag == 'category':
            # handle category ...
        elif element.tag != 'i2':
            continue
        element.clear()
    

    这样,您将省略完整的<i2>节点及其内容,同时能够处理<offers>

    中的任何其他元素

    element.getparent().remove(element)在我的代码(AttributeError)中不起作用。