Google Apps Script导出日历事件触发频率限制错误求助
解决Google Calendar API速率限制错误:
You have been creating or deleting too many calendars or calendar events in a short time 长期以来一直成功使用该脚本,但大约一个月前开始收到错误提示:
You have been creating or deleting too many calendars or calendar events in a short time。每天甚至每周仅添加1-2个事件,不对已有事件做任何修改,但仍触发该错误,脚本已停止工作。
问题根源
你的脚本当前存在几个触发速率限制的核心问题:
- 每次运行都会遍历所有行,包括已同步完成的历史行,每一行都会调用
cal.getEventSeriesById(id)消耗API配额,随着表格行数增加,总请求量会远超实际操作需求。 - 对于已有事件,无论内容是否变化,都会执行
setTitle/setDescription等更新操作,额外增加不必要的API调用。 - 脚本中保留的
debugger语句会导致执行暂停或重复运行,进一步加剧请求频率问题。
可行解决办法
优化方案1:仅处理未同步/需更新的行
新增一个「同步状态」列(比如第8列,索引为7),用来区分行的处理状态:
- 空值:未同步的新行
- "已同步":完成同步且无修改的行
- "需更新":已同步但内容有修改的行
脚本仅处理状态为空白或"需更新"的行,大幅减少API调用次数。
优化方案2:添加请求延迟
在循环中加入短暂延迟,降低请求频率,避免触发Google的速率限制机制。
优化方案3:仅在内容变化时更新事件
对比表格内容与已有事件的信息,只有当标题、时间、描述等字段发生变化时,才执行更新操作,减少无效API调用。
修改后的完整脚本
function onOpen() { var sheet = SpreadsheetApp.getActiveSpreadsheet(); var entries = [{ name : "Export Events", functionName : "exportEvents" }]; sheet.addMenu("Calendar Actions", entries); }; /** * Export events from spreadsheet to calendar */ function exportEvents() { var sheet = SpreadsheetApp.getActiveSheet(); var headerRows = 1; var range = sheet.getDataRange(); var data = range.getValues(); var calId = "mail@gmail.com"; var cal = CalendarApp.getCalendarById(calId); for (let i = 0; i < data.length; i++) { if (i < headerRows) continue; var row = data[i]; var syncStatus = row[7]; // 第8列作为同步状态列 // 跳过已同步且未标记需更新的行 if (syncStatus === "已同步") continue; var date = row[0]; var title = row[1]; var tstart = row[2]; tstart.setDate(date.getDate()); tstart.setMonth(date.getMonth()); tstart.setYear(date.getFullYear()); var tstop = row[3]; tstop.setDate(date.getDate()); tstop.setMonth(date.getMonth()); tstop.setYear(date.getFullYear()); var loc = row[4]; var desc = row[5]; var id = row[6]; let event = null; try { if (id) event = cal.getEventSeriesById(id); } catch (e) { // 忽略事件不存在的异常 } if (!event) { // 创建新事件 var newEvent = cal.createEvent(title, tstart, tstop, {description: desc, location: loc}).getId(); row[6] = newEvent; row[7] = "已同步"; // 标记为已同步 } else { // 仅当内容变化时更新事件 let needUpdate = false; if (event.getTitle() !== title) needUpdate = true; if (event.getDescription() !== desc) needUpdate = true; if (event.getLocation() !== loc) needUpdate = true; if (event.getStartTime().getTime() !== tstart.getTime() || event.getEndTime().getTime() !== tstop.getTime()) needUpdate = true; if (needUpdate) { event.setTitle(title); event.setDescription(desc); event.setLocation(loc); // 更新事件时间(适配事件系列的处理逻辑) var recurrence = CalendarApp.newRecurrence().addDailyRule().times(1); event.setRecurrence(recurrence, tstart, tstop); row[7] = "已同步"; // 更新后重置状态 } } // 添加500毫秒延迟,避免请求过快触发限制 Utilities.sleep(500); } // 将更新后的事件ID和同步状态写回表格 range.setValues(data); }
使用说明
- 在表格中新增第8列,表头命名为「同步状态」。
- 已同步完成的历史行,手动标记为"已同步";若需修改已有事件,将对应行的「同步状态」改为"需更新",运行脚本后会自动更新事件并重置为"已同步"。
- 新行保持「同步状态」为空,运行脚本会自动创建事件并标记为"已同步"。
内容的提问来源于stack exchange,提问作者Sanli
相关产品推荐
相关产品推荐

