【进阶篇-处理读写超限额的问题】代码运行一段时间会报读写超限的问题

因为这里的参考资料实在是太少了,我把我的解决过程写下来跟大家分享一下

1.代码报错示例:

  • gspread.exceptions.APIError: APIError: [429]: Quota exceeded for quota metric ‘Read requests’ and limit ‘Read requests per minute per user’ of service ‘sheets.googleapis.com’ for consumer ‘project_number:587923780411’.
  • gspread.exceptions.APIError: APIError: [429]: Quota exceeded for quota metric ‘Write requests’ and limit ‘Write requests per minute per user’ of service ‘sheets.googleapis.com’ for consumer ‘project_number:587923780411’.

2.解决Read requests

错误代码 429 意味着“请求过多”。
错误信息表明在使用 Google Sheets API 时达到了每分钟读取请求的配额限制。
以下是一些解决此问题的方法:

  1. 减少请求频率
    确保你的代码在每次读取数据时不会频繁调用 API。可以通过添加延迟(例如 time.sleep(1))来控制请求的频率。
  2. 批量读取数据
    尝试一次性读取更多的数据,而不是多次调用 col_values。例如,使用 get_all_values() 方法一次性获取整个工作表的数据。
all_values = sheet.get_all_values()
services_in_sheet = [row[1] for row in all_values]  # 获取 B 列
  1. 优化代码逻辑
    检查你的代码逻辑,确保没有不必要的重复请求。例如,避免在循环中多次调用同一个 API 方法。
  2. 使用服务账户
    如果你在使用 API 限制较低的用户帐户,可以考虑使用服务账户来提高请求配额。
  3. 查看配额限制
    访问 Google Cloud Console 查看你的项目的 API 配额,确保你了解当前的限制,并根据需要进行调整。
  4. 错误处理
    实施错误处理机制,捕获 APIError 异常,并在遇到配额限制时进行重试。可以使用指数退避策略来实现。
import time
from gspread.exceptions import APIError

def safe_get_col_values(sheet, col):
    while True:
        try:
            return sheet.col_values(col)
        except APIError as e:
            if e.response.status_code == 429:  # Quota exceeded
                print("Quota exceeded. Retrying after a delay...")
                time.sleep(60)  # 等待 1 分钟后重试
            else:
                raise  # 其他错误则抛出
  1. 分布请求
    如果可能,可以将请求分布到不同的时间段,避免在短时间内发送大量请求。
    通过以上方法,你应该能够解决 API 请求过多的问题。如果问题仍然存在,请根据具体情况进行调整。

我使用的方法是批量读取数据:

  • 修改前代码
	# 修改前代码
	# 获取 B 列和 C 列的所有值
	services_in_sheet = sheet.col_values(2)  # B 列
	endpoints_in_sheet = sheet.col_values(3)  # C 列
	print("Services in Sheet:", services_in_sheet)  # 打印 B 列的所有值
	print("Endpoints in Sheet:", endpoints_in_sheet)  # 打印 C 列的所有值
  • 修改后代码
	# 修改后代码
    # 获取整个工作表的所有值
    all_values = sheet.get_all_values()
    # 提取 B 列和 C 列的值
    services_in_sheet = [row[1] for row in all_values]  # B 列
    endpoints_in_sheet = [row[2] for row in all_values]  # C 列
    print("Services in Sheet:", services_in_sheet)  # 打印 B 列的所有值
    print("Endpoints in Sheet:", endpoints_in_sheet)  # 打印 C 列的所有值

3.解决Write requests

“Quota exceeded” 的错误,说明应用程序在短时间内进行了过多的写请求,超出了 Google Sheets API 的配额限制。
为了避免这个问题,可以考虑以下几种解决方案:

  1. 减少写请求的频率
    合并更新:如果可以的话,尽量将多个更新合并成一次写操作。
    例如,可以使用 batch_update 方法一次性更新多个单元格。
  2. 使用批量更新
    使用 batch_update 方法可以减少对 API 的调用次数。以下是如何实现的示例:
# 查找符合条件的行
for row_index, row in enumerate(all_values):
    if row[1] == SERVICE_URL_MAPPING.get(service) and row[2] == endpoint:  # B 列和 C 列匹配
        print("Mapped service and endpoint found at row:", row_index + 1)
        print("Updating cells...")

        # 使用批量更新
        cell_updates = [
            {'range': f'E{row_index + 1}', 'values': [[max_qps]]},  # E 列
            {'range': f'F{row_index + 1}', 'values': [[referer_url]]}  # F 列
        ]
        body = {'valueInputOption': 'RAW', 'data': cell_updates}
        sheet.batch_update(body)
        return

print("Mapped service and endpoint combination not found in the sheet.")
  1. 实施重试机制
    在遇到配额超限的错误时,可以实现一个重试机制,稍后再尝试请求。
    可以使用 time.sleep() 来延迟请求。需要使用time库,记得import time
	# 查找符合条件的行
    for row_index, row in enumerate(all_values):
        if row[1] == SERVICE_URL_MAPPING.get(service) and row[2] == endpoint:
            print("Mapped service and endpoint found at row:", row_index + 1)
            print("Updating cells...")

            # 尝试更新,直到成功或达到最大重试次数
            max_retries = 5
            for attempt in range(max_retries):
                try:
                    cell_updates = [
                        {'range': f'E{row_index + 1}', 'values': [[max_qps]]},
                        {'range': f'F{row_index + 1}', 'values': [[referer_url]]}
                    ]
                    body = {'valueInputOption': 'RAW', 'data': cell_updates}
                    sheet.batch_update(body)
                    return  # 成功后退出
                except gspread.exceptions.APIError as e:
                    if e.response.status_code == 429:  # Quota exceeded
                        print(f"Quota exceeded. Retrying in {2 ** attempt} seconds...")
                        time.sleep(2 ** attempt)  # 指数退避
                    else:
                        raise  # 其他错误直接抛出

    print("Mapped service and endpoint combination not found in the sheet.")
  1. 检查配额设置
    访问 Google Cloud Console,检查 API 的配额设置,看看是否可以增加配额。
    配额一般为300,且最大为300
    如何查看配额,请点击

我使用的方法是实施重试机制:

我的代码是挨个写入的,每过20个数据停1s,如果遇到429错误代码就重试。
我使用逐个写入的具体原因如下:

  1. 我的数据量不大
  2. 可能是因为我写入的数据包含链接,总是报错Error during batch update: string indices must be integers,
    数据格式总是不对但我查了很多资料还是解决不了

我的调试语句:

	all_values = sheet.get_all_values()
    cell_updates = []

    for row_index, row in enumerate(all_values):
        if row[1] == mapped_service and row[2] == endpoint:
            print("Mapped service and endpoint found at row:", row_index + 1)

            cell_updates.append({
                'range': f'E{row_index + 1}',
                'values': [[max_qps]]
            })
            cell_updates.append({
                'range': f'F{row_index + 1}',
                'values': [[referer_url]]
            })
            break

    if cell_updates:
        body = {
            'valueInputOption': 'RAW',
            'data': cell_updates
        }
        print("Body content:", body)  # 打印请求体内容以便调试
        print("Cell updates:", cell_updates)  # 打印 cell_updates 以便调试
        
        try:
            sheet.batch_update(body)
            print("Batch update successful.")
        except Exception as e:
            print("Error during batch update:", e)
            import traceback
            traceback.print_exc()
    else:
        print("Mapped service and endpoint combination not found in the sheet.")

报错内容:

Body content: {'valueInputOption': 'RAW', 'data': [{'range': 'E2', 'values': [[844.77]]}, {'range': 'F2', 'values': [['非常长的链接,至少三行']]}]}
Error during batch update: string indices must be integers

上述问题如果有大佬能指导可以在评论区评论,我将万分感谢
所以我的最终代码如下:

    for row_index, row in enumerate(all_values):
        if row[1] in mapped_services and row[2] == endpoint:  # B 列匹配多个映射,C 列匹配
            print("Mapped service and endpoint found at row:", row_index + 1)
            found_match = True  # 找到匹配项

            # 每更新 20 个数据等待 1 秒
            if row_index % 20 == 0 and row_index != 0:
                print("Updated 20 entries, waiting for 1 second...")
                time.sleep(1)  # 等待 1 秒

            print("Updating cells...")
            retry_count = 0
            max_retries = 5  # 最大重试次数
            wait_time = 3  # 初始等待时间

            while retry_count < max_retries:
                try:
                    # 更新 E 列
                    sheet.update_cell(row_index + 1, 5, max_qps)  # E 列
                    # 更新 F 列
                    sheet.update_cell(row_index + 1, 6, referer_url)  # F 列
                    # 更新 H 列
                    sheet.update_cell(row_index + 1, 8, h_value)  # H 列
                    print("Update successful.")
                    break  # 成功后退出重试循环
                except APIError as error:
                    if error.response.status_code == 429:
                        print(f"Rate limit exceeded (429). Waiting for {wait_time} seconds and retrying...")
                        time.sleep(wait_time)
                        wait_time *= 2  # 指数退避
                        retry_count += 1
                    else:
                        print(f"An error occurred: {error}")
                        break  # 其他错误直接退出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值