2013-03-20 97 views
2

我編寫了一些Python代碼來從Gmail服務器獲取電子郵件。這裏是下面的代碼:Python解析中文電子郵件解碼錯誤

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 

英文郵件主題中正確顯示:

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

~~~separator~~~ 

[bonnshore.github.com] Page build successful 

但中國,而不是後:

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

~~~separator~~~ 

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

功能isinstance()顯示字符的類型是「海峽', 所以我試過這個來解決它:

print unicode(mail_subject, 'gb2312') 

和發生錯誤:

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> 

我也tryed的字符直接解碼:

print mail_subject.decode("gb2312") 

,我再次得到了同樣的錯誤!

那麼,如何解決這個問題?

非常感謝! :)

+0

你確定數據實際上是用'gb2312'編碼的嗎?有一個原因,decode_header返回一個元組,包括實際使用的編碼;) – Voo 2013-03-20 06:51:07

回答

0

您的第一次嘗試顯示爲mojibake,因爲您正在將raw gb2312打印到非gb2312控制檯。 decode_header完成作業的第一部分,該作業將頭部看起來像=?iso-8859-1?q?p=F6stal?=轉換成可以顯示給用戶的東西。由於相同的頭文件可以包含多個字符集,因此您得到的是(raw_data,charset)對的列表。

正如你正確猜測的那樣,你應該使用Unicode構造函數將它們轉換爲Unicode - 然後轉換爲UTF-8或任何適合你需要的東西。但是第二次嘗試失敗,因爲代碼頁437無法顯示中文。您的第三個問題來自對decodeencode工作方向的誤解。一個unicode字符串被「編碼」爲一個外部編碼。 (但是,即使成功了,你仍然可以回到將gb2312打印到終端的原始mojibake。)

要測試結果,您需要正確地創建一個Unicode字符串並檢查它或將其打印到文件使用正確的編碼。例如:

>>> 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 
這是中文測試! 

你可以做到這一點,以測試你的作品:

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

最後,需要注意的是獲得由decode_header的第一個項目的回報不足以讓頭部的整體價值,因爲它可以分成幾個塊。你需要加入塊到一個單一的Unicode字符串,這是最好的結合make_header效用函數和unicode構造函數中完成:

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

感覺有悖常理不得不打電話make_headerdecode_header,但它是與當前API,fixed in Python 3

+0

好玩!非常感謝,您的答案只適用於我! – bonn 2013-03-20 07:47:14

+0

@bonn我剛剛發現'Header'支持unicode的構造函數,所以你只需要鍵入'subject = unicode(msg ['subject'])'就能正確解碼爲Unicode。 – user4815162342 2013-03-20 09:15:22

+0

@ 4815162342我會稍後嘗試這個解決方案,它應該是好的,要麼我猜... ...和**終端編碼故障**你在你的答案中提到的是完全正確的,所以我改變了編碼格式爲utf-8支持,現在我可以用'email.Header.decode_header(subject)[0] [0]'來得到一個正確的電子郵件主題,用中文輸入。:) – bonn 2013-03-20 10:04:14