如何通过Google Calendar API与Python筛选资源日历中的重复事件
问题描述
使用Admin Directory和Google Calendar API编写Python脚本,目标是获取Google Workspace域下所有资源日历的重复事件列表,随后修改事件的重复规则使其在90天后结束。目前脚本已能拉取所有资源日历邮箱并获取7个资源日历的事件,但无法筛选出仅重复事件——当前会同时获取单次事件和重复事件。尝试使用event['recurringEventId']时出现报错,求筛选重复事件的方法。
解决方案
一、筛选重复事件的正确方式
直接访问event['recurringEventId']报错是因为单次事件不存在该字段,需先判断字段是否存在。根据你的需求(修改重复规则),推荐获取重复事件的主事件(修改主事件即可更新整个重复系列),具体方式如下:
1. 筛选重复事件主事件(推荐)
重复事件的主事件会包含recurrence字段(存储重复规则),遍历事件时只需判断该字段是否存在即可:
for event in events['items']: # 仅保留包含重复规则的主事件 if 'recurrence' in event: event_list.append(event) print(f"重复事件主事件: {event['summary']} (ID: {event['id']})")
2. 筛选重复事件实例(若需处理单个实例)
如果需要获取重复事件的所有展开实例,需在调用events.list时添加singleEvents=True参数,此时每个实例会包含recurringEventId字段指向主事件ID:
events = service_cal.events().list( calendarId=el, pageToken=page_token, singleEvents=True # 展开重复事件为单个实例 ).execute() for event in events['items']: if 'recurringEventId' in event: print(f"重复事件实例: {event['summary']} (归属主事件ID: {event['recurringEventId']})")
二、修改重复规则(使90天后结束)
获取重复事件主事件后,只需修改其recurrence规则中的UNTIL参数为90天后的日期(RFC3339格式)即可。
完整修改后的代码
import datetime import os.path from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build from googleapiclient.errors import HttpError # API scopes 若修改需删除 token.json SCOPES = [ 'https://www.googleapis.com/auth/calendar.readonly', 'https://www.googleapis.com/auth/calendar.events', 'https://www.googleapis.com/auth/admin.directory.resource.calendar' ] cal_list = [] event_list = [] # 授权流程 creds = None if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES) creds = flow.run_local_server(port=0) with open('token.json', 'w') as token: token.write(creds.to_json()) # 获取所有资源日历邮箱 with build('admin', 'directory_v1', credentials=creds) as service_admin: calendars = service_admin.resources().calendars().list(customer='C03r7ld3j', maxResults=40).execute() for calendar in calendars['items']: cal_list.append(calendar['resourceEmail']) print("资源日历列表:", cal_list) service_cal = build('calendar', 'v3', credentials=creds) page_token = None # 遍历资源日历,筛选重复事件主事件(处理分页) for el in cal_list: while True: events = service_cal.events().list( calendarId=el, pageToken=page_token ).execute() for event in events['items']: if 'recurrence' in event: event_list.append(event) print(f"找到重复事件主事件: {event['summary']} (日历: {el})") page_token = events.get('nextPageToken') if not page_token: break # 修改重复规则为90天后结束 if event_list: end_date = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=90) end_date_rfc3339 = end_date.strftime('%Y%m%dT%H%M%SZ') for event in event_list: new_recurrence = [] for rule in event['recurrence']: if 'RRULE' in rule: # 移除原有UNTIL参数,添加新的结束日期 parts = rule.split(';') filtered_parts = [p for p in parts if not p.startswith('UNTIL=')] filtered_parts.append(f'UNTIL={end_date_rfc3339}') new_rule = ';'.join(filtered_parts) new_recurrence.append(new_rule) else: new_recurrence.append(rule) # 更新事件并捕获异常 try: updated_event = service_cal.events().update( calendarId=event['organizer']['email'], eventId=event['id'], body={'recurrence': new_recurrence} ).execute() print(f"已更新事件: {updated_event['summary']},新结束日期: {end_date_rfc3339}") except HttpError as e: print(f"更新事件失败 {event['id']}: {e}") else: print("未找到任何重复事件")
关键说明
- 分页处理:原代码仅获取第一页事件,修改后通过循环
page_token确保获取所有页的事件 - 时区处理:使用UTC时间计算结束日期,避免时区偏差
- 异常捕获:添加
HttpError捕获,处理API调用过程中的异常
内容的提问来源于stack exchange,提问作者Mark Fraher
相关产品推荐
相关产品推荐

