使用Python从大文件中解析XML

时间:2014-05-20 15:04:08

标签: python xml beautifulsoup

我有一个50MB的xml文件,我需要从中读取一些数据。我的方法是使用Beautifulsoup 4,因为我已经使用该包一段时间了。这段代码显示了我一直在做的事情:

from bs4 import Beautifulsoup

# since the file is big, this line takes minutes to execute
soup = Beautifulsoup(open('myfile.xml'), 'xml')

items = soup.find_all('item')

for item in items:
    name = item['name']
    status = item.find('status').text
    description = item.find('desc').text
    refs = item.findAll('ref')
    data = []
    for ref in refs:
        if 'url' in ref.attrs:
            data.append('%s:%s' % (ref['source'], ref['url']))
        else:
            data.append('%s:%s' % (ref['source'], ref.text))

    do_something(data)

文件并不复杂xml,我只需要读取每个<item>条目上的每个数据:

<item type="CVE" name="some-name" seq="1999-0003">
  <status>Entry</status>
  <desc>A description goes here.</desc>
  <refs>
    <ref source="NAI">NAI-29</ref>
    <ref source="CERT">CA-98.11.tooltalk</ref>
    <ref source="SGI" url="example.com">Some data</ref>
    <ref source="XF">aix-ttdbserver</ref>
    <ref source="XF">tooltalk</ref>
  </refs>
</item>

我正在使用的这个文件更有可能继续增长,所以用块读取它或者不加载整个文件会很棒。我需要帮助解决这个问题。也许除了BS4之外的其他一些软件包速度更快,是否还有一些其他软件包或方法可以避免将整个文件加载到内存中?

2 个答案:

答案 0 :(得分:3)

您想在此处切换到xml.etree.ElementTree() API;它有一个iterparse() iterative parsing function

for event, elem in iterparse(source):
    if elem.tag == "record":
        # do something with the <record> element

        elem.clear()  # clean up

由于您已经在使用BeautifulSoup XML模式,因此您必须已安装lxmllxml实现相同的API,但在C中。请参阅lxml iterparse() documentation

请务必阅读Why is lxml.etree.iterparse() eating up all my memory?以确保在使用lxml时正确清除元素。

默认情况下只发出end个事件;整个标记已被解析,包括子节点。您可以对<item>元素使用此功能:

for event, elem in iterparse(source):
    if elem.tag == "item":
        status = elem.find('status').text
        desc = elem.find('desc').text
        refs = {r.get('source'): r.text for r in elem.findall('./refs/ref')}
        elem.clear()

答案 1 :(得分:0)

请详细了解lxml,它是类似XML的数据查询的瑞士刀。它可以使用多个引擎,包括BeautifoulSoup,您可以使用XPath查询数据,并在XML文件中执行许多高级任务。

这是一种从documentation

解析大文件的方法
with open('xmlfile.xml') as f:
    for event, element in etree.iterparse(f, events=("start", "end")):
        print("%5s, %4s, %s" % (event, element.tag, element.text))

尽管文档显示了许多与解析器交互以仅生成子树的方法。