2013-03-20 4 views
2

J'ai écrit des codes Python pour obtenir des emails du serveur Gmail. Voici le code ci-dessous:Python parse Email chinois décodage Erreur

self.M = imaplib.IMAP4_SSL(self.IMAP_SERVER, self.IMAP_PORT) 
data = self.M.fetch(id,"(RFC822)") 
if data[0] == 'OK': 
    msg = email.message_from_string(data[1][0][1]) 
else: 
    print 'Error!' 
mail_subject = email.Header.decode_header(msg['subject'])[0][0] 
print email.Header.decode_header(msg['subject']) 
print '~~~separator~~~' 
print mail_subject 

sujet anglais mails affiché correctement:

[('[bonnshore.github.com] Page build successful', None)] 

~~~separator~~~ 

[bonnshore.github.com] Page build successful 

mais après le chinois au lieu:

[('\xd5\xe2\xca\xc7\xd6\xd0\xce\xc4\xb2\xe2\xca\xd4\xa3\xa1', 'gb2312')] 

~~~separator~~~ 

╒Γ╩╟╓╨╬─▓Γ╩╘úí 

Fonction isinstance() a montré le type de caractère est « str ', J'ai donc essayé cela pour le résoudre:

print unicode(mail_subject, 'gb2312') 

et se produit une erreur:

File "C:\Python27\lib\encodings\cp437.py", line 12, in encode 
return codecs.charmap_encode(input,errors,encoding_map) 
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-6: 
character maps to <undefined> 

J'ai aussi tryed pour décoder le caractère directement:

print mail_subject.decode("gb2312") 

et je me suis à nouveau la même erreur!

Alors, Comment résoudre ce problème?

Merci beaucoup! :)

+0

Etes-vous sûr que les données sont effectivement codées dans 'gb2312'?Il y a une raison pour laquelle decode_header retourne un tuple incluant l'encodage réellement utilisé;) – Voo

Répondre

0

Votre première tentative s'affiche sous la forme mojibake car vous imprimez la version brute de gb2312 sur une console non-gb2312. decode_header fait la première partie du travail, qui convertit un en-tête qui ressemble à =?iso-8859-1?q?p=F6stal?= en quelque chose qui peut être montré à l'utilisateur. Comme le même en-tête peut contenir plusieurs jeux de caractères, vous obtenez une liste de paires (raw_data, charset).

Vous êtes censé les convertir en Unicode - et ensuite en UTF-8 ou tout ce qui correspond à vos besoins - en utilisant le constructeur Unicode, comme vous l'avez deviné. Mais votre deuxième tentative a échoué car la page de code 437 est incapable d'afficher le chinois. Votre troisième problème vient d'un malentendu de la direction dans laquelle travaillent decode et encode. Une chaîne unicode est "codée" pour un codage externe. (Mais même si cela réussissait, vous seriez toujours de retour au mojibake original de l'impression gb2312 sur votre terminal.)

Pour tester le résultat, vous devrez créer correctement une chaîne Unicode et l'inspecter ou l'imprimer en fichier avec l'encodage correct. Par exemple:

>>> x = unicode('\xd5\xe2\xca\xc7\xd6\xd0\xce\xc4\xb2\xe2\xca\xd4\xa3\xa1', 'gb2312') 
>>> import unicodedata 
>>> map(unicodedata.name, x) # see if it looks chinese 
['CJK UNIFIED IDEOGRAPH-8FD9', 'CJK UNIFIED IDEOGRAPH-662F', 'CJK UNIFIED IDEOGRAPH-4E2D', 'CJK UNIFIED IDEOGRAPH-6587', 'CJK UNIFIED IDEOGRAPH-6D4B', 'CJK UNIFIED IDEOGRAPH-8BD5', 'FULLWIDTH EXCLAMATION MARK'] 
>>> print x     # this works for me because I'm in a UTF-8 locale 
这是中文测试! 

Vous pouvez le faire pour vérifier que cela fonctionne pour vous:

>>> with open('file.txt', 'w') as f: 
... f.write(x.encode('utf-8')) 

Enfin, notez que l'obtention du premier retour de l'élément par decode_header ne suffit pas pour obtenir toute la valeur de l'en-tête , car il peut être divisé en plusieurs morceaux. Vous devez joindre les morceaux en une seule chaîne Unicode, qui est le mieux fait en combinant la fonction d'utilité make_header et le constructeur unicode:

subject_header = msg['subject'] 
subject = unicode(email.header.make_header(email.header.decode_header(subject_header)) 
# now proceed as before... 

On se sent contre-intuitif d'avoir à appeler make_header et decode_header, mais qui est le courant API, fixed in Python 3.

+0

Bien joué! Merci beaucoup, votre réponse fonctionne pour moi! – bonn

+0

@bonn J'ai juste compris que 'Header' supportait le constructeur unicode, donc vous pouvez simplement taper' subject = unicode (msg ['subject']) 'pour que le sujet soit correctement décodé en Unicode. – user4815162342

+0

@ 4815162342 Je vais essayer cette solution plus tard, ça doit être OK soit je suppose ... et le ** défaut d'encodage du terminal ** que vous avez mentionné dans votre réponse est exactement correct, donc j'ai changé le format d'encodage en utf-8 supporté, Maintenant, je peux utiliser 'email.Header.decode_header (sujet) [0] [0]' pour obtenir un sujet d'email correct qui a été tapé en chinois. :) – bonn