当前位置: 首页 > 面试题库 >

对大型XML文件使用Python Iterparse

姬博瀚
2023-03-14
问题内容

我需要用Python编写一个解析器,该解析器可以在没有太多内存(只有2GB)的计算机上处​​理一些非常大的文件(> 2GB)。我想在lxml中使用iterparse做到这一点。

我的文件格式为:

<item>
  <title>Item 1</title>
  <desc>Description 1</desc>
</item>
<item>
  <title>Item 2</title>
  <desc>Description 2</desc>
</item>

到目前为止,我的解决方案是:

from lxml import etree

context = etree.iterparse( MYFILE, tag='item' )

for event, elem in context :
      print elem.xpath( 'description/text( )' )

del context

但是,不幸的是,此解决方案仍在消耗大量内存。我认为问题在于,在与每个“
ITEM”打交道之后,我需要做一些清理空孩子的事情。在处理完数据以进行适当清理之后,谁能提供一些建议以解决我的问题?


问题答案:

试试LizaDaly的fast_iter。处理完元素后elem,它会调用elem.clear()以移除后代,并移除之前的兄弟姐妹。

def fast_iter(context, func, *args, **kwargs):
    """
    http://lxml.de/parsing.html#modifying-the-tree
    Based on Liza Daly's fast_iter
    http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
    See also http://effbot.org/zone/element-iterparse.htm
    """
    for event, elem in context:
        func(elem, *args, **kwargs)
        # It's safe to call clear() here because no descendants will be
        # accessed
        elem.clear()
        # Also eliminate now-empty references from the root node to elem
        for ancestor in elem.xpath('ancestor-or-self::*'):
            while ancestor.getprevious() is not None:
                del ancestor.getparent()[0]
    del context


def process_element(elem):
    print elem.xpath( 'description/text( )' )

context = etree.iterparse( MYFILE, tag='item' )
fast_iter(context,process_element)

Daly的文章非常不错,特别是在处理大型XML文件时。

编辑:fast_iter上面发布的是Daly的修改版本fast_iter。在处理完一个元素之后,它会更加主动地删除不再需要的其他元素。

下面的脚本显示了行为上的差异。特别要注意的是,orig_fast_iter不删除A1元素,而确实删除了元素mod_fast_iter,从而节省了更多内存。

import lxml.etree as ET
import textwrap
import io

def setup_ABC():
    content = textwrap.dedent('''\
      <root>
        <A1>
          <B1></B1>
          <C>1<D1></D1></C>
          <E1></E1>
        </A1>
        <A2>
          <B2></B2>
          <C>2<D></D></C>
          <E2></E2>
        </A2>
      </root>
        ''')
    return content


def study_fast_iter():
    def orig_fast_iter(context, func, *args, **kwargs):
        for event, elem in context:
            print('Processing {e}'.format(e=ET.tostring(elem)))
            func(elem, *args, **kwargs)
            print('Clearing {e}'.format(e=ET.tostring(elem)))
            elem.clear()
            while elem.getprevious() is not None:
                print('Deleting {p}'.format(
                    p=(elem.getparent()[0]).tag))
                del elem.getparent()[0]
        del context

    def mod_fast_iter(context, func, *args, **kwargs):
        """
        http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
        Author: Liza Daly
        See also http://effbot.org/zone/element-iterparse.htm
        """
        for event, elem in context:
            print('Processing {e}'.format(e=ET.tostring(elem)))
            func(elem, *args, **kwargs)
            # It's safe to call clear() here because no descendants will be
            # accessed
            print('Clearing {e}'.format(e=ET.tostring(elem)))
            elem.clear()
            # Also eliminate now-empty references from the root node to elem
            for ancestor in elem.xpath('ancestor-or-self::*'):
                print('Checking ancestor: {a}'.format(a=ancestor.tag))
                while ancestor.getprevious() is not None:
                    print(
                        'Deleting {p}'.format(p=(ancestor.getparent()[0]).tag))
                    del ancestor.getparent()[0]
        del context

    content = setup_ABC()
    context = ET.iterparse(io.BytesIO(content), events=('end', ), tag='C')
    orig_fast_iter(context, lambda elem: None)
    # Processing <C>1<D1/></C>
    # Clearing <C>1<D1/></C>
    # Deleting B1
    # Processing <C>2<D/></C>
    # Clearing <C>2<D/></C>
    # Deleting B2

    print('-' * 80)
    """
    The improved fast_iter deletes A1. The original fast_iter does not.
    """
    content = setup_ABC()
    context = ET.iterparse(io.BytesIO(content), events=('end', ), tag='C')
    mod_fast_iter(context, lambda elem: None)
    # Processing <C>1<D1/></C>
    # Clearing <C>1<D1/></C>
    # Checking ancestor: root
    # Checking ancestor: A1
    # Checking ancestor: C
    # Deleting B1
    # Processing <C>2<D/></C>
    # Clearing <C>2<D/></C>
    # Checking ancestor: root
    # Checking ancestor: A2
    # Deleting A1
    # Checking ancestor: C
    # Deleting B2

study_fast_iter()


 类似资料:
  • 我可以刷新编写器并再次使用相同的编写器向文件中追加更多的xml,如下所示:

  • 问题内容: 我有一个很大的xml文件,其中包含许多子元素。我希望能够运行一些xpath查询。我尝试在Java中使用vtd- xml,但有时会出现内存不足错误,因为xml太大,无法容纳到内存中。是否有替代方法来处理如此大的xml。 问题答案: 尝试http://code.google.com/p/jlibs/wiki/XMLDog 它使用sax执行xpaths,而无需创建xml文档的内存表示形式。

  • 我们需要一个能够存储大量大型csv文件(1000个文件,每天每个1GB)的系统。 还有一些客户端应该连接到此系统并下载csv文件 系统应该容错和可扩展... 我考虑使用Hadoop集群并在其上运行FTP服务器。。。 Hadoop适合这个项目吗? 如果没有,什么技术是合适的?

  • 在读取“100 MB”的大型XML文件并使用xstream对其进行解析时,我遇到了一个问题始终会出现以下错误 下面是解析XML的代码 ClassName是一个普通类,其字段带有xml注释。 然后使用 fileString:将xml文件作为inputstream读取并放入字符串缓冲区后的xml文件。 以上代码适用于小文件,但不适用于大文件,有什么想法吗?

  • 为了在巨大的xml文件中执行XPATH查询,我阅读了许多喜欢VTD-xml的文章,因此我复制了这些文章中的代码: 但当我运行它时没有结果,所以这意味着XML文件没有映射到内存中。。。我的问题是如何在VTD-xml中强制映射xml文件?

  • 问题内容: 我需要一个XML解析器来解析大约1.8 GB的文件。 因此,解析器不应将所有文件加载到内存中。 有什么建议? 问题答案: 除了推荐的SAX解析之外,您还可以使用JDK(包javax.xml.stream)中包含的StAX API(一种SAX演进)。 StAX项目主页:http://stax.codehaus.org/Home 简介:http : //www.xml.com/pub/a/

  • 问题内容: 我目前正在尝试针对更大的csv文件(3.000.000行)使用大量的ID(〜5000)。 我想要所有包含ID文件中ID的csv行。 我的幼稚方法是: 但这需要永远! 有没有更有效的方法来解决这个问题? 问题答案: 尝试 另外,由于您的模式似乎是固定的字符串,因此提供选项可能会加快速度。

  • 问题内容: 我需要阅读几个大(200Mb-500Mb)XML文件,所以我想使用StaX。我的系统有两个模块- 一个用于读取文件(使用StaX);另一个用于读取文件。另一个模块(“解析器”模块)假定获取该XML的单个条目并使用DOM对其进行解析。我的XML文件没有特定的结构-因此我无法使用JaxB。如何向“解析器”模块传递要解析的特定条目?例如: 我想使用StaX来解析该文件-但是每个“项目”条目都