提高速度,Python脚本从邮件中提取Gmail标签

ep6jt1vc  于 5个月前  发布在  Python
关注(0)|答案(1)|浏览(67)

我正在编写一个Python脚本,它可以将Gmail帐户中的每个邮件ID沿着及其添加的标签(完整的标签路径)导出到一个TXT文件中。
脚本本身可以工作,但导出速度大约为每秒2条消息。对于较小的帐户,这很好,但对于较大的帐户,导出可能需要几天,在某些情况下,几周。
是否有方法可以提高脚本的处理速度,或者限制来自Google本身?

def get_label_path(service, label_id):
    label = service.users().labels().get(userId='me', id=label_id).execute()
    label_path = label['name']
    while 'parent' in label:
        label = service.users().labels().get(userId='me', id=label['parent']).execute()
        label_path = label['name'] + '/' + label_path
    return label_path

def get_message_ids_with_labels(service):
    profile = service.users().getProfile(userId='me').execute()

    page_token = None
    with open(OUTPUT_FILE_PATH, 'w') as output_file:
        while True:
            results = service.users().messages().list(userId='me', pageToken=page_token).execute()
            messages = results.get('messages', [])
            
            if not messages:
                break
            
            for message in messages:
                message_id = message['id']
                msg = get_message(service, message_id)
                headers = msg['payload']['headers']
                message_id = next((header['value'] for header in headers if header['name'].lower() == 'message-id'), None)
                label_ids = msg.get('labelIds', [])
                labels = [get_label_path(service, label_id) for label_id in label_ids]
                
                output_file.write(f"Message-ID: {message_id} - Labels: {labels}\n")

            page_token = results.get('nextPageToken')
            if not page_token:
                break

字符串

5q4ezhmt

5q4ezhmt1#

我相信你的目标如下。

  • 您希望减少显示脚本的过程成本。

在您的情况下,以下流程如何?
1.使用Method: users.labels.list将标签列表转换为对象。
1.使用Method: users.messages.lis删除所有消息ID。
1.使用Method: users.messages.get从消息ID中删除标签ID。在这种情况下,使用批处理请求。
1.使用标签列表对象和标签ID创建结果文本。
1.将结果文本写入文件。
当这个流反映在修改后的脚本中时,它变成如下所示。

修改脚本:

请设置OUTPUT_FILE_PATH

OUTPUT_FILE_PATH = "sample.txt" # Please set your output filename.
ar = []

def sample(id, res, err):
    # print(id)
    # print(err)
    ar.append([res["id"], res.get("labelIds", [])])

def get_labels(service):
    obj = service.users().labels().list(userId='me').execute()
    labels = obj.get('labels', [])
    labelObj = {}
    for e in labels:
        labelObj[e["id"]] = e["name"]
    return labelObj

def get_message_ids_with_labels(service):
    # Retrieve label list as an object.
    labelObj = get_labels(service)

    # Retrieve all message IDs.
    messageIds = []
    page_token = ""
    while page_token is not None:
        obj = service.users().messages().list(userId='me', pageToken=page_token, maxResults=500).execute()
        messages = [e["id"] for e in obj.get('messages', [])]
        messageIds += messages
        page_token = obj.get("nextPageToken")
    print(f"Total message IDs: {len(messageIds)}")

    # Retrieve label ids from message IDs.
    for i in range(0, len(messageIds), 100):
        batchIds = messageIds[i:i+100]
        print(f"Processing from {i} to {i + len(batchIds)}")
        batch = service.new_batch_http_request(callback=sample)
        for messageId in batchIds:
            batch.add(service.users().messages().get(userId='me', id=messageId, fields="id,labelIds"))
        batch.execute()

    # Create result texts using the label list object and label IDs.
    arr = []
    for e in ar:
        labelNames = []
        for f in e[1]:
            labelNames.append(labelObj[f])
        arr.append(f"Message-ID: {e[0]} - Labels: {','.join(labelNames)}")
    res = "\n".join(arr)

    # Write the result texts into a file.
    with open(OUTPUT_FILE_PATH, 'w') as output_file:
        output_file.write(res)
    print("Done")

字符串

  • 在这个脚本中,请调用一个函数get_message_ids_with_labels(service)service是一个使用Gmail API的客户端。
  • 运行此脚本时,将使用上述流程创建一个包含Message-ID: ### - Labels: ###的文本文件。

注意:

  • 在这个修改中,它假设您的客户端service可以用于使用Gmail API。请注意这一点。
  • 在我的环境中,大约1分钟可以处理3,000条消息。

参考资料:

新增1:

从你下面的回复来看,
有一个巨大的速度增加。只有一个问题,因为我需要“消息ID”从metadataHeaders[]",
我没有注意到你想从你的问题中检索标题中的Message-ID的值。我以为你想检索Gmail的消息ID。如果标题中的Message-ID的值,那么下面的示例脚本如何?上面的示例脚本被修改了。

示例脚本:

OUTPUT_FILE_PATH = "sample.txt" # Please set your output filename.
ar = []

def sample(id, res, err):
    # print(id)
    # print(err)
    ar.append([res["payload"]["headers"][0]["value"], res.get("labelIds", [])])

def get_labels(service):
    obj = service.users().labels().list(userId='me').execute()
    labels = obj.get('labels', [])
    labelObj = {}
    for e in labels:
        labelObj[e["id"]] = e["name"]
    return labelObj

def get_message_ids_with_labels(service):
    # Retrieve label list as an object.
    labelObj = get_labels(service)

    # Retrieve all message IDs.
    messageIds = []
    page_token = ""
    while page_token is not None:
        obj = service.users().messages().list(userId='me', pageToken=page_token, maxResults=500).execute()
        messages = [e["id"] for e in obj.get('messages', [])]
        messageIds += messages
        page_token = obj.get("nextPageToken")
    print(f"Total message IDs: {len(messageIds)}")

    # Retrieve label ids from message IDs.
    for i in range(0, len(messageIds), 100):
        batchIds = messageIds[i:i+100]
        print(f"Processing from {i} to {i + len(batchIds)}")
        batch = service.new_batch_http_request(callback=sample)
        for messageId in batchIds:
            batch.add(service.users().messages().get(userId='me', id=messageId, format='metadata', metadataHeaders=['Message-ID']))
        batch.execute()

    # Create result texts using the label list object and label IDs.
    arr = []
    for e in ar:
        labelNames = []
        for f in e[1]:
            labelNames.append(labelObj[f])
        arr.append(f"Message-ID: {e[0]} - Labels: {','.join(labelNames)}")
    res = "\n".join(arr)

    # Write the result texts into a file.
    with open(OUTPUT_FILE_PATH, 'w') as output_file:
        output_file.write(res)
    print("Done")

  • 运行此脚本时,将检索邮件头和标签中Message-ID的值。

新增2:

关于您的以下回复,
但是我收到了这个错误“行40,in sample ar.append([res[“payload”][“headers”][0][“value”],res.get(“labelIds”,[])])~^ TypeError:'NoneType' object is not subscriptable”.我假设它与没有标签的消息有关.我假设当没有标签时输出将是“. - Labels:“
在这种情况下,请按如下方式修改上述脚本。

发件人:

def sample(id, res, err):
    # print(id)
    # print(err)
    ar.append([res["payload"]["headers"][0]["value"], res.get("labelIds", [])])

收件人:

def sample(id, res, err):
    # print(id)
    # print(err)
    labelIds = res.get("labelIds", [])
    if "headers" not in res["payload"] or res["payload"]["headers"] is None or len(res["payload"]["headers"]) == 0 or "name" not in res["payload"]["headers"][0] or res["payload"]["headers"][0]["name"] != "Message-ID":
        ar.append(["No Message-ID", [] if labelIds is None else labelIds])
    else:
        ar.append([res["payload"]["headers"][0]["value"], [] if labelIds is None else labelIds])

相关问题