In einem frĂŒheren
Artikel haben wir einen Ansatz zum Erstellen von CSV aus XML in einer von FIAS veröffentlichten Datenbank betrachtet. Die Analyse basierte auf dem DOM-Parser, der die gesamte Datei vor der Verarbeitung in den Speicher lĂ€dt, was dazu fĂŒhrte, dass groĂe Dateien angesichts der begrenzten RAM-GröĂe aufgeteilt werden mussten. Dieses Mal wird empfohlen, zu prĂŒfen, wie gut der SAX-Parser ist, und seine Geschwindigkeit mit dem DOM-Parser zu vergleichen. Die gröĂte der FIAS-Datenbankdateien, HĂ€user mit einer GröĂe von 27,5 GB, wird als Testperson verwendet.
Eintrag
Wir sind gezwungen, die angesehenste Ăffentlichkeit sofort zu verĂ€rgern - versĂ€umen es sofort, die Datenbankdatei der FIX-HĂ€user dem SAX-Parser zuzufĂŒhren. Der Parser stĂŒrzt mit dem Fehler "nicht wohlgeformt (ungĂŒltiges Token)" ab. Und anfangs gab es den Verdacht, dass die Datenbankdatei kaputt war. Nach dem Zerlegen der Datenbank in mehrere kleine Teile wurde jedoch festgestellt, dass die Abweichungen durch eine geĂ€nderte Codierung fĂŒr Hausnummern und / oder GebĂ€ude verursacht wurden. Das heiĂt, die STRUCNUM- oder HOUSENUM-Tags stieĂen auf HĂ€user mit einem Buchstaben, der in einer seltsamen Codierung geschrieben war (nicht UTF-8 und nicht ANSI, in dem das Dokument selbst erstellt wurde):

Wenn diese Codierung durch AusfĂŒhren der Datei ĂŒber die Funktion remove_non_ascii korrigiert wird, hat der Datensatz gleichzeitig die folgende Form:

Eine solche Datei wurde aufgrund zusÀtzlicher Zeichen auch nicht vom Parser absorbiert.
Ich musste mich an regulĂ€re AusdrĂŒcke erinnern und die Datei bereinigen, bevor ich sie in den Parser lud.
Frage: Warum es unmöglich ist, eine normale Datenbank zu erstellen, die fĂŒr die Arbeit ausgelegt ist, erhĂ€lt einen rhetorischen Farbton.
Um die Startfunktionen der Parser auszurichten, entfernen wir das Testfragment von den obigen Inkonsistenzen.
Code zum Löschen der Datenbankdatei vor dem Laden in den Parser:
Codefrom 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)
Der Code ĂŒbersetzt non_ascii-Zeichen in der XML-Datei in normal und entfernt dann das unnötige "" in den Namen von GebĂ€uden und HĂ€usern.
Sax Parser
Nehmen Sie zunĂ€chst eine kleine XML-Datei (58,8 MB). Wir planen, txt oder csv an der Ausgabe abzurufen, was fĂŒr die weitere Verarbeitung in Pandas oder Excel praktisch ist.
Code 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:
Nach dem AusfĂŒhren des Programms erhalten wir die Werte des Python-Wörterbuchs:

Vorlaufzeit: 5-6 Sek.
DOM-Parser
Wir verarbeiten dieselbe Datei, indem wir sie zuerst vollstÀndig in den Speicher laden. Dies ist genau die Methode, die der DOM-Parser verwendet.
Code 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)
Vorlaufzeit 2-3 Sek.
Einen DOM-Parser gewinnen?
GröĂere Dateien
Kleine Dateien spiegeln die RealitĂ€t nicht vollstĂ€ndig wider. Nehmen wir eine Datei, die gröĂer als 353 MB ist (nach der Reinigung, wie oben angegeben).
Schulterergebnisse:
SAX-Parser: 0: 00: 32.090836 - 32 Sek
DOM-Parser: 0: 00: 16.630951 - 16 Sek
Der Unterschied betrĂ€gt das Zweifache der Geschwindigkeit. Dies beeintrĂ€chtigt jedoch nicht den Hauptvorteil des SAX-Parsers - die FĂ€higkeit, groĂe Dateien zu verarbeiten, ohne sie zuvor in den Speicher zu laden.
Es bleibt zu bedauern, dass dieser Vorteil nicht auf die FIAS-Datenbank anwendbar ist, da Vorarbeiten mit Codierungen erforderlich sind.
Datei zur vorlÀufigen Reinigung von Codierungen:
- 353 MB im
Archiv .
Gereinigte DB-Datei fĂŒr Parser-Tests:
- 353 MB im
Archiv .