gspread 批量更新单元格,50k 限制?

3 投票
3 回答
4982 浏览
提问于 2025-04-18 09:38

我之前一直在用 gspread,没遇到什么问题。最近在更新到 Google 表格时,我的单元格数量超过了 50000。结果出现了一个错误:

File "build\bdist.win32\egg\gspread\httpsession.py", line 81, in request raise HTTPError(response) HTTPError

是不是因为更新花了太长时间,导致连接超时了?

我想更新的单元格范围是 A1:CL560。我把输出切割到不到 50000 个单元格,代码就正常工作了。

我用的代码就是在 GitHub 上找到的:

cell_list = worksheet.range('A1:C7')

for cell in cell_list:
    cell.value = 'O_o'

# Update in batch
worksheet.update_cells(cell_list)

50000 个单元格以下一切都正常。不知道该怎么办。

这是我遇到的错误:error: [Errno 10054] An existing connection was forcibly closed by the remote host

我尝试保持连接活着,但还是不行。

3 个回答

0

谷歌表格有复杂度限制。每当一个单元格被更新时,所有引用这个单元格的其他单元格都会重新计算。如果公式变得太复杂或者计算时间太长,表格在计算时就会超时。

为了能够读取超过50000的数据,你可以简化你的表格。请查看这里

1

我用的是GScript而不是Python,但我希望能帮上忙:

当你写“cell.value = 'O_o'”时,其实是在调用一个API,调用次数超过5万次就会出错。最后的update_cells命令可以去掉。如果我没记错的话,你还是会遇到错误。

有几种方法可以避免这个问题,而且速度更快:范围内有一个内置的setValue(Object)函数,所以这一行代码就能满足你的需求:

worksheet.range('A1:C7').setValue('O_o');

或者如果你需要每个字段的值都不一样,你可以先创建一个大小相同的二维数组,然后再把它传给setValues(注意,不是setValue!)函数。

1

有点晚了,但我遇到了这个问题。我通过分批设置值来解决它,下面是我用GoogleScript写的解决方案。虽然这个方法有点复杂,但我在过程中慢慢弄明白的 :)

 function importtxt(url) {   
  var parameters = {method : "get", payload : "", muteHttpExceptions: true, validateHttpsCertificates: false};
  var result = UrlFetchApp.fetch(url, parameters);
  var responseCode = result.getResponseCode();

  var contents = result.getContentText().toString().replace("^[^<]*", "");
  var line = contents.split("\n");

  var j = 0;
  var start = 1;
  var chunk = new Array();
  var chunksize = 5000;
  var rows = contents.length;

  var ImportData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ImportData");
  var range = ImportData.getRange("B2:B").clearContent();

  for (var i = 0; i < rows; i++) {
    if ( line[i]) {
      chunk.push([line[i]]);
      j++;
      if ( j > chunksize || i == contents.length ) {
        j += start - 1;
        var end = j;
        Logger.log("writing chunk to " + start + " : " + j + " : " + chunk.length);
        // write chunk to sheet, i will denote the start
        var range = ImportData.getRange("A" + start + ":A" + j);
        range.setValues(chunk);
        // set variables for next run
        start = end + 1;
        var chunk = new Array();
        j = 0;
      }
    }
  }
  Logger.log("finished - last row was " + end + " but last row should have been " + contents.length);
  if ( j < i ) {
    j += start - 1;
    var end = j;
    Logger.log("writing end chunk to " + start + " : " + j + " : " + chunk.length);
    // write chunk to sheet, i will denote the start
    var range = ImportData.getRange("A" + start + ":A" + j);
    range.setValues(chunk);
  }
  return;
}

撰写回答