Python SAX解析器与python DOM解析器。 Parsim FIAS房屋

在上一篇文章中 ,我们考虑了一种由FIAS发布的数据库上的xml创建CSV的方法。 该解析基于DOM解析器,该解析器在处理之前将整个文件加载到内存中,这导致需要鉴于RAM数量有限而拆分大文件。 这次建议您查看SAX解析器的性能,并将其速度与DOM解析器进行比较。 FIAS数据库文件中最大的文件库是房屋,大小为27.5 GB,将用作测试对象。

参赛作品


我们被迫立即让最受尊敬的公众感到沮丧-立即无法提供SAX解析器,FIAS房屋数据库文件将失败。 解析器因错误“格式不正确(无效的令牌)”而崩溃。 最初,人们怀疑数据库文件已损坏。 但是,在将数据库分为几小部分后,发现偏离是由房屋和/或建筑物编号的编码更改引起的。 也就是说,STRUCNUM或HOUSENUM标记是在房屋中碰到的,它们的字母以一种奇怪的编码(不是UTF-8而不是ANSI,它是文档本身的形式)写成的:



同时,如果通过remove_non_ascii函数运行文件以使编码更清晰,则记录采用以下形式:



由于额外的字符,此类文件也未被解析器吸收。

我必须记住正则表达式并清除文件,然后再将其加载到解析器中。
问题:为什么不可能创建一个正常的数据库,而要进行工作布置却要花很多时间。

为了调整解析器的启动功能,我们从上面的不一致中清除了测试片段。

在将数据库文件加载到解析器之前清除数据库文件的代码:

代号
from datetime import datetime import re from unidecode import unidecode start = datetime.now() f= open('AS_HOUSE.462.xml', 'r',encoding='ANSI') def remove_non_ascii(text): return unidecode(unidecode(text)) for line in f: b=remove_non_ascii(line) for c in re.finditer(r'\w{5}NUM="\d{1,}\"\w\"',b): print(c[0]) c1=c[0][:-3]+c[0][-2] print(c1) b=b.replace(c[0],c1) #    #  f1= open('out.xml', 'w',encoding='ANSI') f1.write(b) f1.close() f.close() print(datetime.now()- start) 


该代码将xml文件中的non_ascii字符转换为普通字符,然后删除建筑物和房屋名称中不必要的“”。

萨克斯解析器


首先,获取一个小的xml文件(58.8 MB),我们计划在输出中获取txt或csv,以便于在pandas或excel中进行进一步处理。

代号
 import xml.sax import csv from datetime import datetime start = datetime.now() class EventHandler(xml.sax.ContentHandler): def __init__(self,target): self.target = target def startElement(self,name,attrs): self.target.send(attrs._attrs.values()) def characters(self,text): self.target.send('') def endElement(self,name): self.target.send('') def coroutine(func): def start(*args,**kwargs): cr = func(*args,**kwargs) cr.__next__() return cr return start with open('out.csv', 'a') as f: # example use if __name__ == '__main__': @coroutine def printer(): while True: event = (yield) print(event,file=f) xml.sax.parse("out.xml", EventHandler(printer())) print(datetime.now()- start) 


执行完程序后,我们得到python字典的值:



交货时间:5-6秒。

DOM解析器


我们通过首先将整个文件加载到内存中来处理同一文件。 这正是DOM解析器使用的方法。

代号
 import codecs,os import xml.etree.ElementTree as ET import csv from datetime import datetime parser = ET.XMLParser(encoding="ANSI") tree = ET.parse("out.xml",parser=parser) root = tree.getroot() Resident_data = open('AS_HOUSE.0001.csv', 'a',encoding='ANSI') csvwriter = csv.writer(Resident_data) attr_names = [ 'HOUSEID', 'HOUSEGUID', 'AOGUID', 'HOUSENUM', 'STRUCNUM', 'STRSTATUS', 'ESTSTATUS', 'STATSTATUS', 'IFNSFL', 'IFNSUL', 'TERRIFNSFL', 'TERRIFNSUL', 'OKATO', 'OKTMO', 'POSTALCODE', 'STARTDATE', 'ENDDATE', 'UPDATEDATE', 'COUNTER', 'NORMDOC', 'DIVTYPE', 'REGIONCODE' ] start = datetime.now() object = [] for member in root.findall('House'): object = [member.attrib.get(attr_name, None) for attr_name in attr_names] csvwriter.writerow(object) Resident_data.close() print(datetime.now()- start) 


前置时间2-3秒。
赢得DOM解析器?

较大的文件


小文件不能完全反映现实。 让我们获取一个大于353 MB的文件(如上所示,清洁后)。

肩部成绩:

SAX解析器:0:00:32.090836-32秒
DOM解析器:0:00:16.630951-16秒

差异是速度的2倍。 但是,这并没有削弱SAX解析器的主要优点-无需先将大文件加载到内存即可处理大文件的能力。
遗憾的是,此优点不适用于FIAS数据库,因为需要进行编码方面的初步工作。

初步清理编码的文件:
- 档案中的 353 MB。

用于解析器测试的纯化数据库文件:
- 档案中的 353 MB。

Source: https://habr.com/ru/post/zh-CN469995/


All Articles