使用gspread遍历Google Sheets所有工作表写入数据时循环提前退出问题
问题场景
我尝试使用Python的gspread库修改一份Google Sheets表格,表格内包含多个格式统一、对应不同房间的工作表,参考示意图:
现有实现代码如下:
room_list = sh.worksheets() room = [] b = 0 for randioom in room_list: temp = str(room_list[b]) print (temp) temp_room_list = re.findall(r"'([^'\\]*(?:\\.[^'\\]*)*)", temp) room.append(temp_room_list[0]) b+=1 print (room) c = 0 d = 1 wks1 = sh.worksheet("List of Applicants") for randission in splitted_email: result = wks1.row_values(wks1.find(str(splitted_email[c][0])).row) c+=1 wks2 = sh.worksheet(str(room[d])) x = 0 y = ['B', 'C', 'D', 'E'] row = 0 try: col = str((len(wks2.col_values("2"))) + 1) for details in range (0, 4, +1): wks2.update(str(y[row] + col), result[x]) x+=1 row+=1 b+=1 except gspread.exceptions.APIError as full: print("Room is full, Going to another room") time.sleep(2) print("Scanning Rooms") d+=1 wks2 = sh.worksheet(str(room[d])) col = str((len(wks2.col_values("2"))) + 1) for details in range (0, 4, +1): wks2.update(str(y[row] + col), result[x]) x+=1 row+=1 b+=1 continue
现有逻辑与问题
上述代码的设计逻辑为:先获取所有工作表名称列表,之后遍历拆分后的邮箱列表,先在List of Applicants工作表中匹配对应邮箱所在行的完整数据,尝试将数据写入目标房间工作表;当写入触发gspread.exceptions.APIError错误(代表当前房间工作表已满)时,将工作表索引d加1,切换到下一个工作表尝试写入。
当前代码存在异常:运行时仅会检查2个工作表(RM 202 8AM和RM 202 10AM),无法遍历全部工作表查找存在剩余写入空间的工作表写入数据,需要修改代码实现遍历所有工作表,遇到满表时自动切换到下一个有空位的工作表,避免循环提前退出。
问题原因
- 工作表名称获取逻辑存在缩进bug:
b+=1写在了for循环外部,配合正则解析工作表对象字符串的冗余逻辑,本身就无法正确拿到全量工作表名。实际上gspread的Worksheet对象自带.title属性可以直接获取表名,完全不需要正则解析。 - 房间切换逻辑仅做单次跳转:
except块里只执行了一次d+=1切换到下一个表,如果第二个表也满了,代码不会继续往后查找,直接抛出异常退出。 - 写入逻辑重复冗余:try块和except块里各写了一遍写入逻辑,很容易出现变量未重置导致的写入错位、索引越界问题。
- 全局索引d不会做边界校验:当d的值超过房间工作表总数时,会直接触发列表索引越界错误。
修复后代码
import gspread import time # 保留你原有的gspread鉴权、表格获取逻辑 # sh = 你的Spreadsheet对象 # 1. 直接获取所有房间工作表,过滤掉申请人总表,无需正则解析 all_ws = sh.worksheets() room_ws_list = [ws for ws in all_ws if ws.title != "List of Applicants"] applicant_ws = sh.worksheet("List of Applicants") write_cols = ['B', 'C', 'D', 'E'] for email in splitted_email: # 提取申请人在总表的对应数据 match_row = applicant_ws.find(str(email[0])).row applicant_info = applicant_ws.row_values(match_row)[:4] write_done = False # 2. 遍历所有房间表找空位,不是仅跳转一次 for room_ws in room_ws_list: try: # 计算当前房间B列的下一个空行 next_empty_row = str(len(room_ws.col_values(2)) + 1) # 逐列写入数据 for idx, col in enumerate(write_cols): room_ws.update(f"{col}{next_empty_row}", applicant_info[idx]) time.sleep(0.1) # 加短延迟避免触发Google API限流 print(f"申请人 {email[0]} 已写入房间 {room_ws.title}") write_done = True break except gspread.exceptions.APIError: print(f"房间 {room_ws.title} 已满,尝试下一个房间") time.sleep(2) continue if not write_done: print(f"所有房间均已满,申请人 {email[0]} 写入失败")
优化说明
- 去掉了冗余的正则解析逻辑,直接通过官方API提供的
.title属性获取工作表名,从根源避免表名获取不全的问题。 - 把单次房间跳转改为全量房间遍历,只要当前房间写入失败就自动尝试下一个,直到找到有空位的房间或遍历完所有房间。
- 合并了重复的写入逻辑,避免变量未重置导致的写入错位问题。
- 增加了全满场景的提示,不会出现无提示崩溃的情况。
如果不需要每次录入新申请人都从第一个房间开始扫描,可以维护一个全局的当前房间索引,每次写入成功后记录当前写到的房间位置,下次从该位置开始扫描,能减少不必要的API调用。
内容的提问来源于stack exchange,提问作者CSAPawn
相关产品推荐
相关产品推荐

