使用列表批量更新Google Sheet时触发APIError[400]问题排查求助
使用列表批量更新Google Sheet时触发APIError[400]问题排查求助
嗨,我最近在尝试用列表自动化更新Google Sheet,但一直碰到APIError 400的问题,实在摸不着头脑——单独用batch_update不结合循环和列表的时候完全正常,一加上各种循环和列表操作就报错,求各位大佬帮忙看看问题出在哪!
我的原代码
import gspread import pandas as pd gc = gspread.service_account(filename="credentials.json") sh = gc.open('GCE MCQ') wks=['2024','2023','2022','2021','2020','2019','2018','2017','2016','2015','2014','2013','2012','2011','2010'] lsts=list() t=open('list3.txt') for line in t: lists=lsts.append(line) x=0 for wk in wks: worksheet = sh.worksheet(wk) body = [ { "requests": [ { "findReplace": { "find": str(x+1), "searchByRegex": True, "range": { "sheetId": worksheet.id, "startColumnIndex": 4, "endColumnIndex":5 }, "replacement":lsts[x] } } ] } ] while x<58: sh.batch_update(body) x=x+1
报错的Traceback
Traceback (most recent call last): File "C:\Users\USER\p4ey\attempt2.py", line 33, in <module> sh.batch_update(body) File "C:\Users\USER\AppData\Local\Programs\Python\Python313\Lib\site-packages\gspread\spreadsheet.py", line 101, in batch_update return self.client.batch_update(self.id, body) File "C:\Users\USER\AppData\Local\Programs\Python\Python313\Lib\site-packages\gspread\http_client.py", line 139, in batch_update r = self.request("post", SPREADSHEET_BATCH_UPDATE_URL % id, json=body) File "C:\Users\USER\AppData\Local\Programs\Python\Python313\Lib\site-packages\gspread\http_client.py", line 128, in request raise APIError(response) gspread.exceptions.APIError: APIError: [400]: Invalid JSON payload received. Unknown name "": Root element must be a message.
我自己的排查思路
我试过去掉列表、循环这些逻辑,直接写死find和replacement的值调用batch_update,完全没问题,所以肯定是循环、列表读取或者请求结构的问题,但我实在找不到具体哪错了。
修正方案(结合大佬们的分析)
后来请教了朋友和查了文档,发现代码里有好几个关键问题,修正后就能正常运行了:
1. 核心问题:请求结构错误
这是导致APIError 400的直接原因!原代码把body定义成了列表包裹字典的格式[ {"requests": [...]} ],但gspread要求的batch_update参数是一个直接包含"requests"键的字典(格式为{"requests": [ ... ]}),外层绝对不能套列表,否则Google API会判定JSON格式无效。
2. 文件读取的小坑
原代码里lists=lsts.append(line)完全没用,因为list.append()返回的是None;而且读取的每行文本会自带换行符\n,替换时会把换行也带进去,应该用line.strip()去掉首尾空白,还得记得用with语句自动管理文件开闭(避免资源泄漏)。
3. 循环逻辑混乱
- 原代码里
for wk in wks遍历所有工作表,但之后的while循环根本没用到遍历结果,只会处理最后一个工作表; body只在循环外定义了一次,x变化后完全没更新请求里的find和replacement值,导致每次调用batch_update都是重复同一个请求;- 把
while循环改成for x in range(58)更清晰,还能避免死循环风险。
4. 效率优化
每次循环都调用sh.batch_update()会频繁请求API,容易触发配额限制,最好把所有要执行的findReplace请求收集到一个列表里,最后一次性提交。
修正后的完整代码
import gspread import pandas as pd gc = gspread.service_account(filename="credentials.json") sh = gc.open('GCE MCQ') wks = ['2024','2023','2022','2021','2020','2019','2018','2017','2016','2015','2014','2013','2012','2011','2010'] lsts = [] # 用with语句安全读取文件,自动处理开闭,同时去掉换行符和空行 with open('list3.txt', 'r') as t: for line in t: stripped_line = line.strip() if stripped_line: lsts.append(stripped_line) # 提前检查列表长度,避免索引越界 if len(lsts) < 58: raise ValueError("list3.txt 里至少要有58条内容哦!") # 收集所有替换请求,最后一次性提交 all_requests = [] # 遍历每个工作表 for wk in wks: worksheet = sh.worksheet(wk) sheet_id = worksheet.id # 对当前工作表执行58次替换 for x in range(58): find_text = str(x + 1) replacement_text = lsts[x] # 构建单个替换请求 find_replace_req = { "findReplace": { "find": find_text, "searchByRegex": True, "range": { "sheetId": sheet_id, "startColumnIndex": 4, "endColumnIndex": 5 }, "replacement": replacement_text } } all_requests.append(find_replace_req) # 一次性提交所有请求 if all_requests: sh.batch_update({"requests": all_requests})
内容来源于stack exchange
相关产品推荐
相关产品推荐

