如何通过Gmail API高效获取邮箱地址以统计高频收发件人?
问题:如何高效批量获取Gmail邮件的收件人/发件人以统计高频邮箱?
我现在需要统计用户邮箱的高频发件人与收件人,原本的计划是获取所有用户邮箱地址存入字典计数后输出,但当前代码处理包含10000+邮件的INBOX标签时表现极差——每次循环都要单独发起API请求,速度慢得难以接受。
我的现有代码如下:
import base64 import email import re import operator from googleapiclient import errors from quickstart import service def find(st): for i in range(0,len(st)): tmp = str(st[i]) for j in range(0,len(tmp)): if tmp[j] == 'T' and tmp[j+1] == 'o' and tmp[j-1] == "'" and tmp[j+2] == "'": return i pass def getTop(n): try: if n == 1: label_ids = "INBOX" else: label_ids = "SENT" user_id = "me" topers = service.users().labels().get(userId = user_id,id = label_ids).execute() count = topers['messagesTotal'] print(count) topers = service.users().messages().list(userId = user_id, labelIds = label_ids).execute() arrId = [] for i in range(0,count): arrId.append(topers['messages'][i]['id']) st = [] for i in range(0,count): message = service.users().messages().get(userId=user_id, id=arrId[i], format = 'metadata').execute() head = message['payload']['headers'] index = find(head) obval = head[index]['value'] tmp = str(obval) tmp =tmp.split('<', 1)[-1] tmp = tmp.replace('>',"") st.append(tmp) cnt = 0 mvalues = {} for mail in st: if not mail in mvalues: mvalues[mail] = 1 else: mvalues[mail]+= 1 sorted_values = sorted(mvalues.items(),key= operator.itemgetter(1)) ln = len(sorted_values) for j in range(1,6): print(sorted_values[-j]) pass except errors.HttpError as error: print('An error occurred: %s' % error)请问在邮件数量较多时,无需每次循环发起请求,最快且最准确的批量获取用户邮箱地址的方法是什么?已经被这个问题困扰4天了,恳请大家帮忙!
回答
嘿,我之前也踩过Gmail API批量请求的坑,针对你遇到的10000+邮件性能问题,给你一套实打实的优化方案,能直接解决你的困扰:
核心优化思路:减少API请求次数 + 精准获取所需数据
1. 用batchGet批量获取邮件,替代循环单请求
Gmail API提供了users.messages.batchGet接口,允许你一次性传入最多100个邮件ID,这能把10000次请求压缩到100次左右,直接砍掉99%的网络开销,速度提升非常明显。
同时,我们可以通过metadataHeaders参数只请求我们需要的To或From字段,减少不必要的数据传输,进一步提升效率。
2. 修复邮件ID获取的分页问题
你当前的messages.list调用只获取了第一页的邮件ID(默认最多100条),完全漏掉了后面的邮件!必须通过pageToken处理分页才能拿到所有邮件ID。
3. 替换低效且易出错的find函数
原来的find函数通过字符串匹配找头部字段的方式非常脆弱,直接遍历headers的name字段匹配要高效准确得多。
优化后的完整代码片段
import re import operator from googleapiclient import errors from quickstart import service def get_top_contacts(n): try: label_ids = "INBOX" if n == 1 else "SENT" user_id = "me" # 第一步:分页获取所有邮件ID(修复原代码的分页问题) arr_id = [] page_token = None max_results_per_page = 500 # 每页最多取500条,减少请求次数 while True: response = service.users().messages().list( userId=user_id, labelIds=label_ids, pageToken=page_token, maxResults=max_results_per_page ).execute() messages = response.get('messages', []) arr_id.extend([msg['id'] for msg in messages]) page_token = response.get('nextPageToken') if not page_token: break print(f"总共获取到 {len(arr_id)} 封邮件ID") # 第二步:批量获取邮件的目标头部字段(To/From) st = [] batch_size = 100 # Gmail batchGet最多支持100个ID target_header = 'To' if label_ids == 'INBOX' else 'From' for i in range(0, len(arr_id), batch_size): batch_ids = arr_id[i:i+batch_size] # 批量请求,只获取需要的头部字段 batch_response = service.users().messages().batchGet( userId=user_id, ids=batch_ids, format='metadata', metadataHeaders=[target_header] ).execute() # 处理批量返回的结果 for msg in batch_response.get('messages', []): headers = msg['payload']['headers'] for h in headers: if h['name'] == target_header: # 提取邮箱地址(兼容带姓名的格式,比如"张三 <zhangsan@example.com>") match = re.search(r'<([^>]+)>', h['value']) if match: email_addr = match.group(1) st.append(email_addr) # 处理纯邮箱地址的情况(没有<>包裹) else: st.append(h['value'].strip()) break # 第三步:统计高频邮箱(原代码的计数逻辑保留,稍微优化写法) contact_count = {} for mail in st: contact_count[mail] = contact_count.get(mail, 0) + 1 # 按次数降序排序,取前5个 sorted_contacts = sorted(contact_count.items(), key=operator.itemgetter(1), reverse=True) print("Top 5 高频联系人:") for idx, (email, count) in enumerate(sorted_contacts[:5], 1): print(f"{idx}. {email}: {count} 次") except errors.HttpError as error: print('An error occurred: %s' % error) # 调用示例:1=统计收件人,2=统计发件人 get_top_contacts(1)
额外优化建议(可选)
- 如果性能要求极高,可以结合异步请求(比如用
aiohttp或Google API的异步客户端)并行发起多个batch请求,但这需要调整代码结构,适合超大量邮件的场景。 - 可以考虑加入缓存机制,如果不需要实时统计,定期缓存统计结果,避免重复请求API。
内容的提问来源于stack exchange,提问作者user8163099
相关产品推荐
相关产品推荐

