我正在遍历电子邮件,转换为纯文本并添加到数据框,以便进行一些机器学习。这对于大多数电子邮件来说都可以正常工作,但是我一直收到此错误,我有点卡住了。
不知道该去哪里。我发现的所有研究都是用日语进行的。
从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
答案 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)