charset-gerechtes Parsen von E-Mails

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Finwood
User
Beiträge: 5
Registriert: Mittwoch 5. Februar 2014, 10:24

Hallo allerseits,

ich möchte E-Mails mit Datenblättern im Plaintext-Format automatisiert auslesen und die Daten in einer MySQL-Datenbank speichern. Folgendes habe ich bereits:

Code: Alles auswählen

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-

import logging
import email
import sys
import re

logging.basicConfig(format='%(asctime)s - %(levelname)s: %(message)s', level=logging.DEBUG)

fp = open(sys.argv[1])
msg = email.message_from_file(fp)
fp.close()

emilData = msg.get_payload(decode = True)
Soweit ist alles klar.
Nun stellt sich allerdings das Problem, dass die Mails von der äußeren Form zwar immer gleich sind, nur leider scheinbar zufällig verschiedene Zeichensätze benutzen. Bisher sind mir UTF-8 und ISO-8859-1 untergekommen, ich kann aber nicht definitiv ausschließen, dass möglicherweise noch weitere auftreten.
UTF-8 ist im body base64-kodiert, was aber mit decode = True (Codeblock oben, Zeile 15) selbstständig abgefangen wird. Als problematisch hat sich jedoch ISO-8859-1 herausgestellt, das kriege ich aus mir unerklärlichen Gründen nicht umcodiert.
Ich habe versucht:

Code: Alles auswählen

charset = msg.get_charset() # Funktioniert nicht, es wird 'None' zurückgegeben

charset = re.compile('charset="([\w\-]+)"').search(msg.get('Content-Type')).group(1) # läuft, bringt aber leider nichts
logging.debug("Charset: %s %s" %(charset, type(charset)))

emilData.decode(charset).encode('utf-8') # vermutlich dilettantisch, funktioniert aber auch nicht
In jedem Fall bekomme ich bei ISO-8859-1 Daten heraus, welche schwer nach Zeichensatzproblemen aussehen:
Geschlecht M�nnlich
Hat jemand eine Ahnung, wo mein Denkfehler liegt?

Gruß, Fin
Finwood
User
Beiträge: 5
Registriert: Mittwoch 5. Februar 2014, 10:24

Problem gelöst!

Ich habe die decode- und encode-Funktion zwar aufgerufen, aber den String, welchen sie zurückgibt, nicht weiterverarbeitet:

Code: Alles auswählen

emilData.decode(charset).encode('utf-8') # funktioniert natürlich nicht
emilData = emilData.decode(charset).encode('utf-8') # so muss das aussehen
Trotzdem einen herzlichen Dank für die schnelle Hilfe!

Viele Grüße,
Finwood
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wieso codierst Du die Strings eigentlich unmittelbar nach dem Dekodieren wieder?

Und wer ist dieser "Emil" :twisted: ? (SCNR)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Finwood: Ich würde das Kodieren ja weiter nach hinten verschieben und die Datenbank machen lassen, beziehungsweise bei der Datenbankverbindung die Kodierung angeben, so dass man bei Texten mit der Datenbank mit `unicode`-Objekten arbeiten kann. Dann kann man die Datenbankeinstellungen transprarent(er) ändern ohne das Programm nach expliziten Kodierungsaufrufen durchforsten zu müssen.

PS: Wer ist eigentlich dieser Emil? SCNR ;-)

PPS: Ich hätte es *sofort* abschicken sollen. :-)
Finwood
User
Beiträge: 5
Registriert: Mittwoch 5. Februar 2014, 10:24

Moin!
Hyperion hat geschrieben:Wieso codierst Du die Strings eigentlich unmittelbar nach dem Dekodieren wieder?
Ich möchte sichergehen, dass am Ende Unicode herauskommt, ist das unnötig?
BlackJack hat geschrieben:Ich würde das Kodieren ja weiter nach hinten verschieben und die Datenbank machen lassen, beziehungsweise bei der Datenbankverbindung die Kodierung angeben, so dass man bei Texten mit der Datenbank mit `unicode`-Objekten arbeiten kann.
Meine Datenbank ist in Unicode (MySQL-Collation uft8_general_ci), auch die Kommunikation zwischen python und der Datenbank läuft in UTF-8:

Code: Alles auswählen

db.set_character_set('utf8')
Ist in diesem Fall die Encodierung des ganzen nicht mehr nötig?

LG Fin
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Finwood hat geschrieben:Ich möchte sichergehen, dass am Ende Unicode herauskommt, ist das unnötig?
Unicode ist nicht gleich UTF-8. Du hast einen Unicode-String vorliegen. Wie dessen Aufbau im Speicher genau ist ist völlig uninteressant für dich und hat sich in der Entwicklung von Python auch geändert. Du nimmst aber explizit ein Encoding mit UTF-8 vor und hast damit eben keinen Unicode-String mehr, sondern eine Bytesequenz in der der Unicode-String nach UTF-8 codiert ist.
Finwood
User
Beiträge: 5
Registriert: Mittwoch 5. Februar 2014, 10:24

/me hat geschrieben:Unicode ist nicht gleich UTF-8.
Stimmt, vielen Dank, das war mir bisher nicht klar.
/me hat geschrieben:Wie dessen Aufbau im Speicher genau ist ist völlig uninteressant für dich
Das ist leider nicht ganz richtig, ich muss die Daten mit regulären Ausdrücken parsen und den String in viele kleine Teilstücke zerlegen, was mit Python 2.7 irgendwie nicht funktioniert.
Ist es vertretbar, die Strings als UTF-8 zu kodieren, oder fällt das in die Kategorie "bad habit"?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Finwood hat geschrieben: Das ist leider nicht ganz richtig, ich muss die Daten mit regulären Ausdrücken parsen und den String in viele kleine Teilstücke zerlegen, was mit Python 2.7 irgendwie nicht funktioniert.
Deswegen muss Dich der Aufbau im Speicher aber dennoch nicht interessieren ;-)

Was genau funktioniert denn nicht?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Finwood hat geschrieben:Das ist leider nicht ganz richtig, ich muss die Daten mit regulären Ausdrücken parsen und den String in viele kleine Teilstücke zerlegen, was mit Python 2.7 irgendwie nicht funktioniert.
Doch, doch, das geht. Ich habe schon so viel mit Unicode und regulären Ausdrücken unter Python 2 gearbeitet, dass ich mitbekommen hätte wenn es da ein Problem gäbe. Zeig mal Code.
Finwood
User
Beiträge: 5
Registriert: Mittwoch 5. Februar 2014, 10:24

Hyperion hat geschrieben:Was genau funktioniert denn nicht?
/me hat geschrieben:Doch, doch, das geht.
Ich habe mich vertan, das Problem lag nicht in den regulären Ausdrücken sondern darin, dass ich versucht habe Unicode-Strings mit nicht-Unicode-Strings direkt zu vergleichen. Und logischerweise habe ich an diesen Stellen keine Übereinstimmung bekommen...

Jetzt werden die Daten aus den Mails ausschließlich dekodiert und nach der Verarbeitung als Unicode an die Datenbank geschickt.

Vielen Dank für die Denkanstöße und Lösungsansätze, das Problem hat sich sozusagen selbst gelöst!
Antworten