使用gspread读取高负载谷歌表格耗时过长的优化咨询
谷歌表格数据提取代码优化问题
我近期开发了一段代码,通过URL和表格标题(标题范围已做保护以确保稳定)从5个高负载谷歌表格中提取数据表格。这些表格未规范化,每个工作表中可能有1-5个表格,起始位置不固定(如A3、B5等),因此采用标题定位。
耗时较长的代码片段
# 从BQ表中查询表格所在工作表信息 hoja = query_select_keys_tablas(columnas='NOMBRE_HOJA',where='NOMBRE_TABLA',filtro=hoja_key).iloc[0,0] gc = gspread.authorize(credentials=credentials) # 这行耗时可以理解 ws = gc.open_by_key(url_pais).worksheet(hoja) # LINE 1: 耗时超10秒的三行之一(取决于URL和表格) table_location = ws.find(hoja_key) table_start_row = table_location.row + 1 table_start_col = table_location.col # LINE 2: 另一行耗时10秒的代码,用于确定表格结束位置 columns_in_sheet = ws.row_values(table_start_row) # 因表格相邻但间隔一空列,通过此步骤区分表格边界 columns_in_sheet = columns_in_sheet[table_start_col-1:] try: table_end_col = columns_in_sheet.index('') + table_start_col - 1 except ValueError: table_end_col = len(columns_in_sheet) + table_start_col - 1 table_range = f'{get_column_letter(table_start_col)}{table_start_row}:{get_column_letter(table_end_col)}' # LINE 3: 耗时最长的代码行 table = ws.get(table_range,value_render_option = 'UNFORMATTED_VALUE', date_time_render_option = 'FORMATTED_STRING') df = pd.DataFrame(table) df.columns = df.iloc[0] df = df[1:] df = df[df[df.columns[0]] != '']
当前问题
代码运行耗时不稳定,有时需1分钟,有时仅4秒,首次运行同一变量组合时速度始终较慢。想确认是否遗漏参数可提升gspread方法速度;若无法优化,能否通过修改或移除标记的3行代码来提升效率?该代码是大型脚本的一部分,分析师每日可能需运行20次,希望得到优化建议。
优化建议
1. 批量读取+本地处理,减少API请求
当前的ws.find、ws.row_values、ws.get是三次独立的谷歌API请求,每次请求都有网络延迟和API处理开销。改为单次批量读取工作表数据,再在本地完成标题定位、边界判断和表格截取,直接砍掉两次API调用:
# 一次性读取目标工作表的全部数据(若工作表过大,可限制范围如'A1:Z1000') all_data = ws.get_all_values( value_render_option='UNFORMATTED_VALUE', date_time_render_option='FORMATTED_STRING' ) # 本地查找标题位置(替代LINE 1的ws.find) table_location = None for row_idx, row in enumerate(all_data): if hoja_key in row: table_location = { 'row': row_idx + 1, # 转换为gspread的1-based索引 'col': row.index(hoja_key) + 1 } break if table_location: table_start_row = table_location['row'] + 1 table_start_col = table_location['col'] # 本地处理列边界(替代LINE 2的ws.row_values) columns_in_sheet = all_data[table_start_row - 1] # 转换为0-based索引 columns_in_sheet = columns_in_sheet[table_start_col - 1:] try: table_end_col = columns_in_sheet.index('') + table_start_col - 1 except ValueError: table_end_col = len(columns_in_sheet) + table_start_col - 1 # 本地截取目标表格(替代LINE 3的ws.get) # 从起始行开始,截取指定列范围,过滤空行 table = [] for row in all_data[table_start_row - 1:]: filtered_row = row[table_start_col - 1:table_end_col] if any(filtered_row): # 跳过全空行 table.append(filtered_row)
2. 启用API响应缓存
首次运行慢主要是谷歌API冷启动和网络请求的问题,用requests-cache缓存API响应,重复请求直接读缓存,大幅提升重复运行速度:
import requests_cache # 初始化带缓存的会话,缓存有效期1小时(可根据数据更新频率调整) session = requests_cache.CachedSession('gspread_cache', expire_after=3600) gc = gspread.authorize(credentials, session=session)
注意:如果表格数据更新频繁,缩短expire_after时长,比如设置为600秒(10分钟)。
3. 复用核心对象
把gc授权对象和ws工作表对象的初始化移到脚本的全局/初始化部分,分析师每日运行20次时,只需初始化一次,避免重复授权和工作表加载的耗时。
4. 优化gspread方法参数
- 保持
value_render_option='UNFORMATTED_VALUE',避免读取格式信息,减少数据传输量。 - 若明确表格大致范围,在批量读取时指定具体范围(如
ws.get('A1:Z500', ...)),避免读取冗余数据。
内容的提问来源于stack exchange,提问作者Bruno Acosta
相关产品推荐
相关产品推荐

