错误UnicodeDecodeError:“ iso2022_jp”编解码器无法解码位置7572-7573中的字节:非法的多字节序列

时间:2019-07-20 09:19:52

标签: python-3.x unicode html-email

我正在遍历电子邮件,转换为纯文本并添加到数据框,以便进行一些机器学习。这对于大多数电子邮件来说都可以正常工作,但是我一直收到此错误,我有点卡住了。

不知道该去哪里。我发现的所有研究都是用日语进行的。

从bs4导入BeautifulSoup 从html2text导入HTML2Text

import pandas as pd

import easyimap
import getpass
import email

from datetime import datetime
from email.utils import parsedate_to_datetime




def to_text(html, rehtml=False):
    parser = HTML2Text()
    parser.wrap_links = False
    parser.skip_internal_links = True
    parser.inline_links = True
    parser.ignore_anchors = True
    parser.ignore_images = True
    parser.ignore_emphasis = True
    parser.ignore_links = True
    text = parser.handle(html)
    text = text.strip(' \t\n\r')
    if rehtml:
        text = text.replace('\n', '<br/>')
        text = text.replace('\\', '')
    return text 

imap_password = getpass.getpass()


user = 'email@email.com'
host = 'outlook.office365.com'
password = imap_password


folders =  ('"INBOX/Americas/Not Raised"', '"INBOX/Americas/Raised"', '"INBOX/APAC/Not Raised"', '"INBOX/APAC/Raised"', '"INBOX/Consolidated"', 
            '"INBOX/Consolidated/Not Raised"', '"INBOX/Consolidated/Raised"', '"INBOX/EMEA"', '"INBOX/EMEA/Not Raised"', '"INBOX/EMEA/Raised"')


df = pd.DataFrame(columns=['Subject','Sender','From','To','Body','References','content_type', 'local_date_time', 
                          'Classification', 'in_reply_to','return_path', 'mime_version', 'message_id'])


for mailbox in folders:

    #Connect to mailbox read_only = True to ensure the mail is not marked as read.
    imapper = easyimap.connect(host, user, password, mailbox,read_only=True)

    #fetch each mail up to limit and return email data and add to a dataframe

    for mail_id in imapper.listids(limit=10000):
        mail = imapper.mail(mail_id, include_raw=True)
        #convert body to text using to_text function and add to dataframe
        df.loc[mail_id, ['Body']] = to_text(mail.body, rehtml=False)
        #return mail features to dataframe
        df.loc[mail_id, ['Subject']] = mail.title
        df.loc[mail_id, ['Sender']] = mail.sender
        df.loc [mail_id, ['From']] = mail.from_addr
        df.loc [mail_id, ['To']] = mail.to
        df.loc [mail_id, ['References']] = mail.references
        df.loc [mail_id, ['content_type']] = mail.content_type
        #converting the date to datetime and taking account of time difference changes
        date_= mail.date
        df.loc [mail_id, ['local_date_time']] = datetime.fromtimestamp(parsedate_to_datetime(date_).timestamp()).strftime('%Y-%m-%d %H:%M:%S')
        #parsing the keyword data from the raw mail data to provide the classification
        raw_data = mail.raw
        email_message = email.message_from_bytes(raw_data)
        df.loc [mail_id, ['Classification']] = email_message['Keywords']
        df.loc [mail_id, ['in_reply_to']] = mail.in_reply_to
        df.loc [mail_id, ['return_path']] = mail.return_path
        df.loc [mail_id, ['mime_version']] = mail.mime_version
        df.loc [mail_id, ['message_id']] = mail.message_id

所有电子邮件都应添加到数据框。回溯错误显示为:

---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-11-e9627be1e6e3> in <module>
     54 
     55     for mail_id in imapper.listids(limit=10000):
---> 56         mail = imapper.mail(mail_id, include_raw=True)
     57         #convert body to text using to_text function and add to dataframe
     58         df.loc[mail_id, ['Body']] = to_text(mail.body, rehtml=False)

/anaconda3/lib/python3.6/site-packages/easyimap/easyimap.py in mail(self, uid, include_raw)
    198         typ, content = self._mailer.uid('fetch', uid, self._fetch_message_parts)
    199         if typ == 'OK':
--> 200             mail = _parse_email(content, include_raw=include_raw)
    201             return mail
    202         else:

/anaconda3/lib/python3.6/site-packages/easyimap/easyimap.py in _parse_email(data, include_raw)
    246     if not isinstance(string_or_bytes_message, str):
    247         encoding = chardet.detect(string_or_bytes_message)
--> 248         string_or_bytes_message = string_or_bytes_message.decode(encoding.get('encoding'))
    249     if not isinstance(string_or_bytes_uid, str):
    250         encoding = chardet.detect(string_or_bytes_uid)

UnicodeDecodeError: 'iso2022_jp' codec can't decode bytes in position 7572-7573: illegal multibyte sequence

4 个答案:

答案 0 :(得分:1)

easyimap库使用chardet库来猜测您一封电子邮件的编码。但是,猜测编码不是必须完成的任务。因此chardet猜测该消息已使用“ iso2022_jp”进行编码,但是由于这是错误的,因此后续的解码步骤将失败。

我不确定您可以做很多事情。 如果您可以识别出有问题的消息,则可以尝试找出其真正的编码。 如果成功,则可能有一种方法可以覆盖猜测步骤并告诉easyimap –也许encoding=方法中有一个可选的imapper.mail()参数,您必须检查文档。

答案 1 :(得分:0)

猜测编码总是很困难并​​且容易出错。即使您猜到了“正确”的编码,数据也可能包含用于该编码的非法字符。

首先要检查的是:电子邮件Content-type标头是否具有Charset属性?如果是这样,那可能是正确的字符集,应该使用它,而不要退回到chardet。

答案 2 :(得分:0)

ISO-2022-JP是一种怪异的编码,具有多种形式化为各种程度的变体。 ①等字符在某些变体中有效,但在基本编码中无效。如果您可以手动指定用于邮件的编码,请尝试以下一种方法:

ISO-2022-JP-1
ISO-2022-JP-2
ISO-2022-JP-3
ISO-2022-JP-2004
CP932

CP932是Windows编码,Outlook会假装ISO-2022-JP是相同的东西,即使不是。 Mac有时会使用1/2/3变体,特别是当发送的字符不是基本编码时。

如果您可以将原始邮件粘贴到某处,将会有所帮助,尽管我知道出于隐私原因这可能是不可能的。

答案 3 :(得分:0)

将问题电子邮件发送到文件即可。

    let model = News(value: jsonObject)