由于“\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)