解析多个大型XML文件并写入CSV

时间:2019-09-07 07:22:51

标签: python xml python-3.x csv

我大约有1000个XML文件,每个文件的大小为250 MB。我需要从中提取一些数据并写入CSV。 不能有重复的条目。

我有一个配备4GB RAM和AMD A8处理器的系统。

我已经在这里浏览过一些以前的文章,但是它们似乎并不能回答我的问题。

我已经用Python编写了代码,并在示例XML上对其进行了测试,并且效果很好。

但是,当我在所有文件上使用它并且必须中途终止该过程时,它非常慢(每个文件将近15分钟)。

什么是加快该过程的最佳解决方案?

这是代码

path='data/*.xml'
t=[]
for fname in glob.glob(path):
    print('Parsing ',fname)
    tree=ET.parse(fname)
    root=tree.getroot()
    x=root.findall('//Article/AuthorList//Author')
    for child in x:
        try:
            lastName=child.find('LastName').text
        except AttributeError:
            lastName=''
        try:
            foreName=child.find('ForeName').text
        except AttributeError:
            foreName=''
        t.append((lastName,foreName))
    print('Parsed ',fname)

t=set(t)

我想要最快的方法来获取条目,没有任何重复的值。 (也许存储在某个数据库中,而不是存储在变量t中,由于有更多的可用RAM,因此将每个条目存储在数据库中会加速吗?-无论我需要采用哪种方法进行操作)

1 个答案:

答案 0 :(得分:4)

不要将结果写入Python列表,而是创建具有UNIQUE约束的数据库表,并将所有结果写入该表。完成所有写操作后,将DB表转为csv。

如果您不希望有任何其他依赖关系来写入数据库,建议您使用sqlite3,因为它在任何最新的Python安装中都是开箱即用的。

以下是一些入门代码:

import sqlite3
conn = sqlite3.connect('large_xml.db')  # db will be created
cur = conn.cursor()
crt = "CREATE TABLE foo(fname VARCHAR(20), lname VARCHAR(20), UNIQUE(fname, lname))"
cur.execute(crt)
conn.commit()

path='data/*.xml'
for fname in glob.glob(path):
    print('Parsing ',fname)
    tree=ET.parse(fname)
    root=tree.getroot()
    x=root.findall('//Article/AuthorList//Author')
    count = 0
    for child in x:
        try:
            lastName=child.find('LastName').text
        except AttributeError:
            lastName=''
        try:
            foreName=child.find('ForeName').text
        except AttributeError:
            foreName=''
        cur.execute("INSERT OR IGNORE INTO foo(fname, lname) VALUES(?, ?)", (foreName, lastName))
        count += 1
        if count > 3000:  # commit every 3000 entries, you can tune this
            count = 0
            conn.commit()

    print('Parsed ',fname)

填充数据库后,按以下步骤将其转储到csv:

sqlite3 -header -csv large_xml.db "select * from foo;" > dump.csv

此外,尝试使用更快的解析方式。 此外,如果.text属性通常是可用的, 以下内容可能比异常处理要快:

lastName = getattr(child.find('LastName'), 'text', '')