You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 17:56:00