【问题标题】:Python LXML iterparse function: memory not getting freed while parsing a huge XMLPython LXML iterparse函数:解析巨大的XML时内存没有被释放
【发布时间】:2018-01-29 02:27:42
【问题描述】:

我在 Python 中的 LXML 库的帮助下解析大型 XML(~500MB)。我已经将 BeautifulSoup 与 lxml-xml 解析器一起用于小文件。但是当我遇到巨大的 XML 时,它效率很低,因为它读取整个文件一次,然后解析它。

我需要解析一个 XML 以获取根到叶路径(最外面的标记除外)。
例如。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE A>
<A>
    <B>
        <C>
            abc
        </C>
        <D>
            abd
        </D>
    </B>
</A>

上面的 XML 应该给出键和值作为输出(根到叶路径)。

A.B.C = abc
A.B.D = abd

这是我为解析它而编写的代码:
(ignore1 和 ignore2 是需要忽略的标签,tu.clean_text() 是删除不必要字符的函数)

def fast_parser(filename, keys, values, ignore1, ignore2):
    context = etree.iterparse(filename, events=('start', 'end',))

    path = list()
    i = 0
    lastevent = ""
    for event, elem in context:
        i += 1
        tag = elem.tag if "}" not in elem.tag else elem.tag.split('}', 1)[1]

        if tag == ignore1 or tag == ignore2:
            pass
        elif event == "start":
            path.append(tag)
        elif event == "end":
            if lastevent == "start":
                keys.append(".".join(path))
                values.append(tu.clean_text(elem.text))

            # free memory
            elem.clear()
            while elem.getprevious() is not None:
                del elem.getparent()[0]
            if len(path) > 0:
                path.pop()
        lastevent = event

    del context
    return keys, values

解析大文件ibm.com/developerworks/xml/library/x-hiperfparse/#listing4已经参考了下面这篇文章

这是 top 命令的截图。大约 500 MB XML 文件的内存使用量超过 2 GB。我怀疑内存没有被释放。

我已经解决了几个 StackOverflow 问题。但这没有帮助。请指教。

【问题讨论】:

    标签: python xml parsing lxml


    【解决方案1】:

    我从https://stackoverflow.com/a/7171543/131187 获取代码,删除了 cmets 和打印语句,并添加了一个合适的func 来获取它。我不想猜测处理一个 500 Mb 文件需要多少时间!

    即使在写func 时,我也没有做任何原创,采用了原作者使用 xpath 表达式“ancestor-or-self::*”来提供您想要的绝对路径。

    但是,由于此代码更符合原始脚本,因此它可能不会泄漏内存。

    import lxml.etree as ET
    
    input_xml = 'temp.xml'
    for line in open(input_xml).readlines():
        print (line[:-1])
    
    def mod_fast_iter(context, func, *args, **kwargs):
        for event, elem in context:
            func(elem, *args, **kwargs)
            elem.clear()
            for ancestor in elem.xpath('ancestor-or-self::*'):
                while ancestor.getprevious() is not None:
                    del ancestor.getparent()[0]
        del context
    
    def func(elem):
        content = '' if not elem.text else elem.text.strip()
        if content:
            ancestors = elem.xpath('ancestor-or-self::*')
            print ('%s=%s' % ('.'.join([_.tag for _ in ancestors]), content))
    
    print ('\nResult:\n')
    context = ET.iterparse(open(input_xml , 'rb'), events=('end', ))
    mod_fast_iter(context, func)
    

    输出:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE A>
    <A>
        <B>
            <C>
                abc
            </C>
            <D>
                abd
            </D>
        </B>
    </A
    
    Result:
    
    A.B.C=abc
    A.B.D=abd
    

    【讨论】:

    • 成功了,我会检查我的代码有什么问题。非常感谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多