gspread 批量更新单元格,50k 限制?
我之前一直在用 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 个回答
谷歌表格有复杂度限制。每当一个单元格被更新时,所有引用这个单元格的其他单元格都会重新计算。如果公式变得太复杂或者计算时间太长,表格在计算时就会超时。
为了能够读取超过50000的数据,你可以简化你的表格。请查看这里。
我用的是GScript而不是Python,但我希望能帮上忙:
当你写“cell.value = 'O_o'”时,其实是在调用一个API,调用次数超过5万次就会出错。最后的update_cells命令可以去掉。如果我没记错的话,你还是会遇到错误。
有几种方法可以避免这个问题,而且速度更快:范围内有一个内置的setValue(Object)函数,所以这一行代码就能满足你的需求:
worksheet.range('A1:C7').setValue('O_o');
或者如果你需要每个字段的值都不一样,你可以先创建一个大小相同的二维数组,然后再把它传给setValues(注意,不是setValue!)函数。
有点晚了,但我遇到了这个问题。我通过分批设置值来解决它,下面是我用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;
}