如何通过Apps Script批量获取Google Drive多份表单响应并写入Spreadsheet
需求可行性结论
该需求完全可以通过Google Apps Script实现,无需额外接入第三方服务。
现有代码失效原因
appendRow(form.getItemResponses()) 无法正常写入数据的核心问题有两点:
- 方法调用层级错误:
getItemResponses()是单条提交响应(FormResponse对象)的内置方法,直接在Form表单实例上调用会直接抛出「方法不存在」的错误,无法获取有效数据。 - 传入参数类型不符合要求:
appendRow()仅接收一维基础类型数组,数组中每个元素对应新行的一列,仅支持字符串、数字、时间、布尔值这类可直接写入单元格的基础类型。即使你从单条响应对象上取到getItemResponses()的返回值,它也是一组ItemResponse类的实例对象,封装了题目ID、题型、响应值等结构化属性,不是可直接写入的纯值,直接传入只会写入无意义的对象标识或空值。
正确实现方案
你的场景里每份副本表单都预设了不可编辑的单选项作为唯一标识,不需要从用户提交内容里提取该字段,直接从表单题目配置中读取即可,避免不同表单响应混淆。完整实现逻辑如下:
- 提前配置结果表格地址、已收集的表单ID列表
- 遍历每个表单ID,通过Form服务打开表单(Drive服务仅能读取文件元数据,无法获取表单响应结构,必须配合FormApp使用)
- 读取当前表单预设的唯一标识字段值
- 拉取当前表单所有提交记录,将每条记录处理为基础值组成的一维数组,再调用
appendRow()写入表格
可直接参考以下可运行代码,替换对应配置项即可:
function syncAllFormResponsesToSheet() { // 配置项 - 替换为你自己的资源信息 const TARGET_SPREADSHEET_ID = '替换为存储结果的Google表格ID'; const TARGET_SHEET_NAME = '表单响应汇总'; const ID_FIELD_TITLE = '替换为你设置的表单ID字段的题目标题'; // 替换为你已经收集完成的所有副本表单ID数组 const formIdList = ['表单ID1', '表单ID2', '表单ID3' /* 补全剩余200+表单ID */]; const sheet = SpreadsheetApp.openById(TARGET_SPREADSHEET_ID).getSheetByName(TARGET_SHEET_NAME); // 首次运行写入表头,表头顺序和后续写入的内容顺序保持一致即可,已写入表头可注释掉下一行 if (sheet.getLastRow() === 0) { sheet.appendRow(['表单唯一标识', '提交时间', '题目1', '题目2', '题目3' /* 按实际表单题目补全 */]); } // 遍历所有表单拉取响应 formIdList.forEach(formId => { try { const form = FormApp.openById(formId); // 直接从表单题目配置中读取预设的唯一标识值,无需依赖用户提交 const idFieldItem = form.getItems(FormApp.ItemType.MULTIPLE_CHOICE) .find(item => item.getTitle() === ID_FIELD_TITLE) .asMultipleChoiceItem(); const formIdentifier = idFieldItem.getChoices()[0].getValue(); // 拉取当前表单所有提交记录 const allResponses = form.getResponses(); allResponses.forEach(response => { // 初始化行数据,先放入表单标识、提交时间 const rowData = [formIdentifier, response.getTimestamp()]; // 遍历单条提交的所有题目响应,提取实际值 response.getItemResponses().forEach(itemRes => { // 跳过ID字段,避免重复写入 if (itemRes.getItem().getTitle() === ID_FIELD_TITLE) return; // 调用getResponse()拿到用户提交的实际内容,推入行数据数组 rowData.push(itemRes.getResponse()); }); // 此时rowData是符合要求的基础值一维数组,可正常写入 sheet.appendRow(rowData); }) } catch (err) { // 单个表单读取失败时打印日志,不中断整体遍历流程 console.log(`表单[ID:${formId}]读取失败:${err.message}`); } }) }
优化注意事项
- 如果表单包含多选题,
getResponse()会返回选项组成的数组,直接写入单元格会自动用逗号拼接,需要拆分多列展示可单独加逻辑处理。 - 200+表单如果累计提交量较大,单次执行可能触发Apps Script 6分钟执行时长限制,可以给脚本设置定时触发器,同时记录已同步的响应ID,避免重复写入。
- 如果副本表单是通过脚本批量生成的,可以在生成环节直接把表单ID、对应标识值提前写入结果表,省去后续遍历表单读取标识的步骤,执行效率更高。
内容的提问来源于stack exchange,提问作者kevin
相关产品推荐
相关产品推荐

