由于“\r\n”,无法正确解析来自 Gmail 的电子邮件
Failing to parse email from Gmail correcty because of `\r\n`
我在 Gmail 中有一封简单的电子邮件,如下所示:
Hi all
@alice - please prepare XXX for tomorrow
@bob - please prepare YYY for tomorrow
best,
Z
我想获取它,解析它并按换行符拆分,所以我会得到一个包含 5 个元素的列表:
['Hi all','@alice ...', '@bob ...', 'best,','Z']
但出于某种原因,在句子中我得到了 \r\n
这让我将这行分成 2 行,尽管在原始电子邮件中没有换行。
我将其解析如下(在获得正确的凭据之后)
txt = service.users().messages().get(userId=user.email, id=email_msg['id']).execute()
payload = txt["payload"]
headers = payload["headers"]
parts = payload.get("parts")[0]
data = parts["body"]["data"]
data = data.replace("-", "+").replace("_", "/")
decoded_message = str(base64.b64decode(data), "utf-8")
split = decoded_message.splitlines()
final_split = list(filter(None, split))
但我收到的消息如下所示:
Hi all\r\n\r\n@alice - please prepare XXX\r\nfor tomorrow\r\n@bob - please prepare YYY for tomorrow\r\nr\nbest,\n\rZ
所以如果我按 \r\n
或 \n
拆分,我会得到无效结果
当您使用 b64decode()
解码数据时,您得到的不是字符串,而是字节字符串。 Here's 对差异的极好解释。在尝试解析消息之前,您必须将其转换为常规字符串。
您可以通过 运行宁 .decode("utf-8")
来完成此操作。然后你就可以使用 .splitlines()
拆分消息。
txt = service.users().messages().get(userId=user.email, id=email_msg['id']).execute()
payload = txt["payload"]
headers = payload["headers"]
parts = payload.get("parts")[0]
data = parts["body"]["data"]
data = data.replace("-", "+").replace("_", "/")
decoded_data = base64.b64decode(data)
decoded_message = decoded_data.decode("utf-8") # decodes the byte string
split = decode_message.splitlines() # splits the message into a list
final_split = list(filter(None, split)) # this removes the blank lines
运行 .decode()
消息上的内容将更改为:
Hi all\r\n\r\n@alice - please prepare XXX\r\nfor tomorrow\r\n@bob - please prepare YYY for tomorrow\r\nr\nbest,\n\rZ
转原帖:
Hi all
@alice - please prepare XXX for tomorrow
@bob - please prepare YYY for tomorrow
best,
Z
然后在 .splitlines()
之后你会得到这个列表:
['Hi all', '', '@alice...', '@bob...', '', 'best,', 'Z']
注意空行对应的是空字符串。要摆脱它们,您可以 运行 最后一行 final_split = list(filter(None, split))
,这将为您提供所需的内容。还有其他methods:
['Hi all', '@alice...', '@bob...', 'best,', 'Z']
顺便说一句,我没有为此安装 BeautifulSoup
,但如果你想使用它,你可能想在解码字节字符串后添加它。
正如 Daniel 在评论中所建议的那样,我使用 HTML 数据来正确提取消息:
我定义了 HTML
解析器:
from html.parser import HTMLParser
from io import StringIO
def extract_text(html_text: str) -> str:
class MLStripper(HTMLParser):
def __init__(self):
super().__init__()
self.reset()
self.strict = False
self.convert_charrefs = True
self.text = StringIO()
def handle_data(self, d):
self.text.write(d)
def get_data(self):
return self.text.getvalue()
def strip_tags(html):
s = MLStripper()
s.feed(html)
return s.get_data()
cleaned_html_text = html_text.replace('</div>', '\n</div>').replace('\r\n', '')\
.replace('<br>', '\n').replace('\xa0', ' ')
return strip_tags(cleaned_html_text)```
然后 运行 它在 HTML
:
parts = payload.get("parts")[1] # take the HTML part
data = parts["body"]["data"]
data = data.replace("-", "+").replace("_", "/")
decoded_message = str(base64.b64decode(data), "utf-8")
extracted_message = extract_text(html_text=decoded_message)
我在 Gmail 中有一封简单的电子邮件,如下所示:
Hi all
@alice - please prepare XXX for tomorrow
@bob - please prepare YYY for tomorrow
best,
Z
我想获取它,解析它并按换行符拆分,所以我会得到一个包含 5 个元素的列表:
['Hi all','@alice ...', '@bob ...', 'best,','Z']
但出于某种原因,在句子中我得到了 \r\n
这让我将这行分成 2 行,尽管在原始电子邮件中没有换行。
我将其解析如下(在获得正确的凭据之后)
txt = service.users().messages().get(userId=user.email, id=email_msg['id']).execute()
payload = txt["payload"]
headers = payload["headers"]
parts = payload.get("parts")[0]
data = parts["body"]["data"]
data = data.replace("-", "+").replace("_", "/")
decoded_message = str(base64.b64decode(data), "utf-8")
split = decoded_message.splitlines()
final_split = list(filter(None, split))
但我收到的消息如下所示:
Hi all\r\n\r\n@alice - please prepare XXX\r\nfor tomorrow\r\n@bob - please prepare YYY for tomorrow\r\nr\nbest,\n\rZ
所以如果我按 \r\n
或 \n
拆分,我会得到无效结果
当您使用 b64decode()
解码数据时,您得到的不是字符串,而是字节字符串。 Here's 对差异的极好解释。在尝试解析消息之前,您必须将其转换为常规字符串。
您可以通过 运行宁 .decode("utf-8")
来完成此操作。然后你就可以使用 .splitlines()
拆分消息。
txt = service.users().messages().get(userId=user.email, id=email_msg['id']).execute()
payload = txt["payload"]
headers = payload["headers"]
parts = payload.get("parts")[0]
data = parts["body"]["data"]
data = data.replace("-", "+").replace("_", "/")
decoded_data = base64.b64decode(data)
decoded_message = decoded_data.decode("utf-8") # decodes the byte string
split = decode_message.splitlines() # splits the message into a list
final_split = list(filter(None, split)) # this removes the blank lines
运行 .decode()
消息上的内容将更改为:
Hi all\r\n\r\n@alice - please prepare XXX\r\nfor tomorrow\r\n@bob - please prepare YYY for tomorrow\r\nr\nbest,\n\rZ
转原帖:
Hi all
@alice - please prepare XXX for tomorrow
@bob - please prepare YYY for tomorrow
best,
Z
然后在 .splitlines()
之后你会得到这个列表:
['Hi all', '', '@alice...', '@bob...', '', 'best,', 'Z']
注意空行对应的是空字符串。要摆脱它们,您可以 运行 最后一行 final_split = list(filter(None, split))
,这将为您提供所需的内容。还有其他methods:
['Hi all', '@alice...', '@bob...', 'best,', 'Z']
顺便说一句,我没有为此安装 BeautifulSoup
,但如果你想使用它,你可能想在解码字节字符串后添加它。
正如 Daniel 在评论中所建议的那样,我使用 HTML 数据来正确提取消息:
我定义了 HTML
解析器:
from html.parser import HTMLParser
from io import StringIO
def extract_text(html_text: str) -> str:
class MLStripper(HTMLParser):
def __init__(self):
super().__init__()
self.reset()
self.strict = False
self.convert_charrefs = True
self.text = StringIO()
def handle_data(self, d):
self.text.write(d)
def get_data(self):
return self.text.getvalue()
def strip_tags(html):
s = MLStripper()
s.feed(html)
return s.get_data()
cleaned_html_text = html_text.replace('</div>', '\n</div>').replace('\r\n', '')\
.replace('<br>', '\n').replace('\xa0', ' ')
return strip_tags(cleaned_html_text)```
然后 运行 它在 HTML
:
parts = payload.get("parts")[1] # take the HTML part
data = parts["body"]["data"]
data = data.replace("-", "+").replace("_", "/")
decoded_message = str(base64.b64decode(data), "utf-8")
extracted_message = extract_text(html_text=decoded_message)