You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过Google App Script获取Google表格单元格编辑历史?

获取Google Sheets单元格编辑历史的脚本方案

你观察到的那个POST请求确实是Google Sheets加载单元格编辑历史的核心接口,不过直接模拟这个请求需要处理几个关键参数和权限问题——毕竟Google并没有把这个接口开放为正式的公开API。下面是一步步的可行方案:

一、关键参数的获取方式

你已经识别了大部分参数的含义,这里补充如何在Google Apps Script中直接获取它们:

  • Spreadsheet ID:从表格URL里提取,或者用SpreadsheetApp.getActiveSpreadsheet().getId()在脚本中自动获取。
  • Sheet ID:当前工作表的ID,通过SpreadsheetApp.getActiveSheet().getSheetId()就能拿到,和你在请求里看到的"629843311"格式完全一致。
  • 单元格位置参数:请求里的selection数组是0索引的:
    • 单个单元格(比如B10,即第10行第2列)对应的核心参数是:[null, SHEET_ID, 9, 1](行号-1=9,列号-1=1),范围部分写成[[null, SHEET_ID, 9, 10, 1, 2]](起始行9,结束行10;起始列1,结束列2)
  • clientRevision:表格的当前修订版本号,用SpreadsheetApp.getActiveSpreadsheet().getLastRevisionId()获取即可,或者直接留空(部分场景下Google会自动兼容)。
  • token:这是最麻烦的临时会话令牌,不过在Google Apps Script中可以利用UrlFetchApp的内置身份验证跳过手动获取步骤——脚本运行时会自动使用当前用户的权限发送请求。

二、示例脚本:发送请求并解析编辑历史

下面是一个简化的脚本,模拟POST请求并提取编辑者和时间戳,最终写入表格:

function getCellEditHistory() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const spreadsheetId = ss.getId();
  const sheet = ss.getActiveSheet();
  const sheetId = sheet.getSheetId();
  
  // 目标单元格:这里以B10为例(第10行,第2列),可自行修改
  const targetRow = 10;
  const targetCol = 2;
  
  // 构造selection参数(严格对应抓包的格式)
  const selection = JSON.stringify([
    ss.getId(), // 替换为抓包时的第一个数字参数,若无效可尝试留空
    [null, [null, sheetId.toString(), targetRow - 1, targetCol - 1], 
     [[null, sheetId.toString(), targetRow - 1, targetRow, targetCol - 1, targetCol]]]
  ]);
  
  // 构造多部分表单请求体
  const boundary = "----WebKitFormBoundaryFpwmP3acru2z5xQc";
  const payload = [
    `--${boundary}`,
    'Content-Disposition: form-data; name="selection"',
    '',
    selection,
    `--${boundary}`,
    'Content-Disposition: form-data; name="clientRevision"',
    '',
    ss.getLastRevisionId(),
    `--${boundary}`,
    'Content-Disposition: form-data; name="includeDiffs"',
    '',
    'true',
    `--${boundary}--`
  ].join("\r\n");
  
  // 请求配置
  const options = {
    method: "POST",
    headers: {
      "accept": "*/*",
      "content-type": `multipart/form-data; boundary=${boundary}`,
      "x-same-domain": "1"
    },
    payload: payload,
    followRedirects: true,
    muteHttpExceptions: true // 方便查看错误信息
  };
  
  // 发送请求并解析响应
  const url = `https://docs.google.com/spreadsheets/d/${spreadsheetId}/blame?includes_info_params=true`;
  const response = UrlFetchApp.fetch(url, options);
  const responseText = response.getContentText();
  
  try {
    const data = JSON.parse(responseText);
    // 注意:实际响应的JSON结构可能需要调整索引,建议先打印responseText查看
    const editRecord = data[1][1][0][2];
    if (editRecord) {
      const editorName = editRecord[0][0];
      const editTime = new Date(editRecord[1] * 1000); // 转换秒级时间戳为日期
      
      // 将结果写入表格(示例写入D1-E2区域)
      sheet.getRange("D1").setValue("最后编辑者");
      sheet.getRange("D2").setValue(editorName);
      sheet.getRange("E1").setValue("编辑时间");
      sheet.getRange("E2").setValue(editTime);
    } else {
      SpreadsheetApp.getUi().alert("未找到该单元格的编辑历史");
    }
  } catch (e) {
    SpreadsheetApp.getUi().alert(`解析出错:${e.message}\n响应内容:${responseText}`);
  }
}

三、注意事项和可能的坑

  • 权限授权:运行脚本时需要授权https://www.googleapis.com/auth/spreadsheetshttps://www.googleapis.com/auth/script.external_request权限,确保脚本能访问表格和发送外部请求。
  • 接口稳定性:这个是Google内部接口,没有官方文档,参数或响应格式可能随时变更。如果脚本失效,需要重新抓包分析新的请求结构。
  • 响应解析:示例中的data[1][1][0][2]是基于你提供的请求推测的路径,实际运行时建议先打印responseText查看JSON结构,再调整解析索引。

你可以先运行脚本查看响应内容,再根据实际的JSON结构修改解析逻辑,就能顺利提取编辑历史并写入表格了。

内容的提问来源于stack exchange,提问作者Timogavk

火山引擎 最新活动