我写了一些Python代码来从Gmail服务器获取电子邮件。以下是代码:
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()显示字符的类型是'str', 所以我试着用它来解决它:
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>
我也试着直接解码这个角色:
print mail_subject.decode("gb2312")
我再次遇到同样的错误!
那么,如何解决这个问题呢?
非常感谢! :)
答案 0 :(得分:0)
您的第一次尝试显示为mojibake,因为您正在将原始gb2312打印到非gb2312控制台。 decode_header
执行作业的第一部分,即将看起来像=?iso-8859-1?q?p=F6stal?=
的标题转换为可以向用户显示的标题。由于相同的标头可以包含多个字符集,因此您获得的是(raw_data
,charset
)对的列表。
你应该使用Unicode构造函数将它们转换为Unicode - 然后转换为UTF-8或任何适合您需要的东西 - 正如您所猜测的那样。但是你的第二次尝试失败了,因为代码页437无法显示中文。您的第三个问题来自于对decode
和encode
工作方向的误解。 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_header
和decode_header
,这是违反直觉的,但那是当前的API,fixed in Python 3。