使用 Python 读取大的 .mbox 文件

Bas*_*asj 14 python email mbox

我想读取来自 Gmail 备份的 3GB .mbox 大文件。这有效:

import mailbox
mbox = mailbox.mbox(r"D:\All mail Including Spam and Trash.mbox")
for i, message in enumerate(mbox):
    print("from   :",message['from'])
    print("subject:",message['subject'])
    if message.is_multipart():
        content = ''.join(part.get_payload(decode=True) for part in message.get_payload())
    else:
        content = message.get_payload(decode=True)
    print("content:",content)
    print("**************************************")

    if i == 10:
        break
Run Code Online (Sandbox Code Playgroud)

但仅前 10 条消息就需要 40 秒以上。

有没有更快的方法来使用 Python 访问大的 .mbox 文件?

tri*_*eee 16

mbox这是一个快速而肮脏的尝试,用于实现一个生成器来逐条消息地读入文件。我选择简单地从From 分隔符中丢弃信息;我猜真正的mailbox库可能会提供更多信息,当然,这仅支持读取,而不支持搜索或写回输入文件。

#!/usr/bin/env python3

import email
from email.policy import default

class MboxReader:
    def __init__(self, filename):
        self.handle = open(filename, 'rb')
        assert self.handle.readline().startswith(b'From ')

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        self.handle.close()

    def __iter__(self):
        return iter(self.__next__())

    def __next__(self):
        lines = []
        while True:
            line = self.handle.readline()
            if line == b'' or line.startswith(b'From '):
                yield email.message_from_bytes(b''.join(lines), policy=default)
                if line == b'':
                    break
                lines = []
                continue
            lines.append(line)
Run Code Online (Sandbox Code Playgroud)

用法:

with MboxReader(mboxfilename) as mbox:
    for message in mbox:
        print(message.as_string())
Run Code Online (Sandbox Code Playgroud)

该参数(当然,如果您愿意,policy=default也可以使用任何策略来代替)选择Python 3.3 中引入并在 3.6 中成为正式版本的现代库。如果您需要支持较旧的 Python 版本defaultEmailMessage在美国失去理智并在白宫安放一个邪恶的小丑之前 更简单的时候,你会想要省略它;但实际上,新的 API 在很多方面都更好。

  • 我很惊讶这不在邮箱标准库模块中。大多数 Python 标准库都是迭代器友好的。感谢您提供! (3认同)
  • 不,内置的“mailbox.mbox”不会将整个存档加载到 RAM 中。但它确实预加载并缓存了一个(小)TOC 结构,该结构将每个消息位置(int)映射到其文件字节偏移量(两个 int)。首次访问时创建此目录可能需要一些时间。 (3认同)