You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:10:31