【问题标题】:lxml iterparse fills memory despite on clear尽管清除,lxml iterparse 仍会填充内存
【发布时间】:2014-12-13 13:25:24
【问题描述】:

我正在尝试解析 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>

【问题讨论】:

标签: python xml parsing lxml iterparse


【解决方案1】:

我也和iterparse打了一阵子,现在终于知道如何正确使用它了,所以这是我的智慧之言: 使用iterparse时:

  1. 确保使用cElementTree 实现

  2. 确保清除所有不需要的元素。如果您有一个非常复杂且具有深层嵌套结构的 XML,这一点尤其重要。

所以让我们假设您的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()

这样,您将省略完整的 &lt;i2&gt; 节点及其内容,同时能够处理 &lt;offers&gt; 中的任何其他元素

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

【讨论】:

  • 您好,感谢您的回答。但是,您提供的代码看起来与一年多前接受的答案中提供的代码没有任何不同,因此看起来您复制了它。还有你提出的两点已经被提问者应用了。你能解释一下你认为这个答案的附加价值是什么吗?
  • 嗨 trincot,感谢您的提问。在我在 Stackoverflow 和其他地方读到的关于 iterparse 的所有示例中,XML 结构总是超级简单,而据报道文件非常庞大。我正在处理相反的问题:文件
【解决方案2】:

您将解析文件两次,第一次是保留所有 category 标记并删除 offer 标记,这对于 1000 个 category 标记不会占用那么多内存。

但是第二次只删除 category 标签而保留所有 450000 个 offer 标签,这就是构建树需要大量内存的原因。

在这种情况下,最好不要使用 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...

【讨论】:

  • element.getparent().remove(element) 可能还不够。您可能需要删除兄弟姐妹。见the related question
猜你喜欢
  • 1970-01-01
  • 2018-12-09
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
  • 1970-01-01
  • 2018-09-16
  • 2014-08-18
  • 1970-01-01
相关资源
最近更新 更多