未记录的 Sheet API 限制问题

JSm*_*ith 2 javascript google-apps-script http-status-code-413 google-sheets-api

我已经看过人们遇到类似问题的帖子,但找不到明确的答案。

我尝试使用以下代码行检索 264735 个插槽的二维数组:

  var optionalArguments = {majorDimension: "ROWS",
                     valueRenderOption: "FORMULA",
  };
  var sourceValuesObject = Sheets.Spreadsheets.Values.get(spreadsheetId, rangeA1Notation, optionalArguments)
Run Code Online (Sandbox Code Playgroud)

但这是我得到的:

响应代码:413。消息:响应太大。

这看起来很奇怪,因为我看不到这种限制写在任何地方,加上如果 300000 个或更少的单元格导致 API 错误,用户如何获取大量数据。

我尝试过拆分请求并且它有效,但这使我的代码变得更加复杂且速度更慢,而且在尝试将值更新回工作表范围时我得到空响应。

我指向正确的方向吗?这是正常的吗?有解决方法吗?

编辑: 这是一个示例电子表格

首先,我尝试使用循环Sheets.Spreadsheets.Values.get 内部来获取分割范围for,并且它有效。

做同样的事情batchGet会给我同样的错误,所以我想单元格内的数据太大了。

Tan*_*ike 5

这个解决方法怎么样?

实验:

此实验使用您共享的示例电子表格。

当 UrlFetchApp 直接调用 Sheets API 的端点时,如果响应大小大于 50 MB(52,428,800 Byte),则返回小于 50 MB 的响应。50 MB 的大小是由于 UrlFetchApp 的限制。另一方面,在Advanced Google Service中,它无法确认这种情况,因为超过限制时就会发生错误。因此,通过使用 UrlFetchApp,可以确认您的情况的错误原因。所以首先,我使用以下脚本确认了这一点。

var spreadsheetId = "#####";
var range = "'Copie de Feuille 1'!A1:JE1000";
var url = "https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheetId + "/values/" + range + "?majorDimension=ROWS&valueRenderOption=FORMULA";
var res = UrlFetchApp.fetch(url, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
Logger.log(res.getContentText().length.toString())
var values = JSON.parse(res.getContentText());
Run Code Online (Sandbox Code Playgroud)

当上面的脚本运行时,52428450返回。并且在最后一行出现“未终止的字符串文字”错误。这意味着该对象是不完整的。从这个结果可以发现,一次调用values.get无法检索到范围为 的值'Copie de Feuille 1'!A1:JE1000这和我的评论的情况是一样的。

在您的示例电子表格中,发现错误发生的范围边界是'Copie de Feuille 1'!A1:JE722。当尝试从 range 检索值时'Copie de Feuille 1'!A1:JE723,会发生错误。从中检索的值的大小'Copie de Feuille 1'!A1:JE722为 52,390,229 字节。这小于 50 MB(52,428,800 字节)。from 的大小'Copie de Feuille 1'!A1:JE723为 52,428,450 字节,与 的值相同'Copie de Feuille 1'!A1:JE1000。由此发现超出了UrlFetchApp的限制。

解决方法:

为了避免此错误并检索所有值,作为一种解决方法,我认为我想建议它分割从电子表格检索值的范围。但在你的问题中,你想要速度。所以我想提出以下示例脚本。

  1. 创建请求。
  2. 使用 获取创建的请求UrlFetchApp.fetchAll()
    • 通过UrlFetchApp.fetchAll(),每个请求都可以异步处理。
    • 在高级 Google 服务的 Sheets API 中,无法使用此功能。另外,在values.batchGet中,由于所有检索到的值都超出了限制,因此会发生错误。
    • 这样,使用的处理成本UrlFetchApp.fetchAll()就变得比高级Google服务的Sheets API要低。

示例脚本:

var ranges = ["'Copie de Feuille 1'!A1:JE500", "'Copie de Feuille 1'!A501:JE1000"]; // This was used from the shared spreadsheet. So please modify this for your environment.
var token = ScriptApp.getOAuthToken();
var requests = ranges.map(function(e) {
  return {
    method: "get",
    url: "https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheetId + "/values/" + e + "?majorDimension=ROWS&valueRenderOption=FORMULA",
    headers: {Authorization: "Bearer " + token},
    muteHttpExceptions: true,
  }
});
var res = UrlFetchApp.fetchAll(requests);
var values = res.reduce(function(ar, e) {
  Array.prototype.push.apply(ar, JSON.parse(e.getContentText()).values);
  return ar;
}, []);
Logger.log(values.length) // 1000
Logger.log(values[0].length) // 265
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 如果您想使用该脚本,请确认在 API 控制台启用了 Sheets API。
  • 合并数组时,如果出现数组限制错误,请使用各个数组,不要合并数组。
  • 当使用高级 Google 服务的 Sheets API 时,在 的范围内也不会发生错误'Copie de Feuille 1'!A1:JE722,而在 处发生错误'Copie de Feuille 1'!A1:JE723。这个结果和 的结果是一样的UrlFetchApp

参考:

  • 这个答案帮助我非常有效地处理 Google Apps 脚本 http 请求太大(>50MB)的问题。清晰的答案和干净的代码。干杯! 对于我的情况,我必须使用 Array.prototype.push.apply(ar, JSON.parse(e.getContentText("UTF-8"))); (UTF-8 并且没有 .values,因为我是从 REST API 而不是电子表格获取的) (2认同)