2

我编写了一些 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")

我又遇到了同样的错误!

那么,如何解决这个问题?

非常感谢!:)

4

1 回答 1

1

您的第一次尝试显示为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_headerand感觉违反直觉decode_header,但这是当前的 API,在 Python 3 中已修复

于 2013-03-20T07:15:34.960 回答