使用For循环上传照片到Google Photos时出现上传令牌无效报错
问题原因
- 缺少单张上传请求的错误校验:当前代码直接将
requests.post的返回内容解码后加入token列表,没有判断请求是否成功。如果某次上传因为网络波动、图片损坏、接口限流返回非200状态,返回的内容不是有效上传token,批量创建时就会触发400错误。 - 文件资源泄漏:代码用
open(image_path, 'rb').read()读取图片后没有主动关闭文件句柄,长时间运行会耗尽系统文件描述符,导致后续图片读取失败,上传内容为空,返回无效token。 - 重复加载鉴权token:每次循环都读取本地pickle文件加载鉴权token,不必要的IO操作不仅拖慢速度,也有概率出现文件读取异常,导致鉴权失败,上传请求返回错误内容。
修复方案
核心优化点
- 单张上传后先判断响应状态码,只有200 OK的返回内容才作为有效上传token存入列表,失败的请求可以重试3次后跳过并记录日志。
- 鉴权token加载移到循环外部,避免重复读取本地文件。
- 使用
with上下文管理器读取图片,自动释放文件句柄。 - 增加请求间隔,避免触发Google Photos API的流量限制。
修复后参考代码
import os import time import pickle import requests i=0 k=0 tokens = [] failed_files = [] upload_url = 'https://photoslibrary.googleapis.com/v1/uploads' service = Service(API_SERVICE_NAME, VERSION, SCOPES, SECRET_ID=cred) # 鉴权token移到循环外只加载一次 token = pickle.load(open('token_photoslibrary_v1.pickle', 'rb')) headers_base = { 'Authorization': 'Bearer ' + token.token, 'Content-type': 'application/octet-stream', 'X-Goog-Upload-Protocol': 'raw', } for file in files: if file.lower().endswith(".jpg"): i = i + 1 image_path = os.path.join(image_dir, file) # 复制基础头,添加文件名参数 headers = headers_base.copy() headers['X-Goog-File-Name'] = file headers['X-Goog-Upload-File-Name'] = view+file # 用with读取文件,自动释放资源 with open(image_path, 'rb') as f: img = f.read() # 重试机制,最多3次 retry = 0 upload_success = False while retry < 3: response = requests.post(upload_url, data=img, headers=headers) if response.status_code == 200: tokens.append(response.content.decode('utf-8')) upload_success = True break retry += 1 time.sleep(1) # 重试前等待1秒 if not upload_success: failed_files.append(file) print(f"文件{file}上传失败,已跳过") # 避免请求过快,单张上传后等待0.1秒,可根据实际情况调整 time.sleep(0.1) if i%50==0 and i>0: #call every 50 k = k + 1 print(f'{k}批次正在上传,累计失败文件数:{len(failed_files)}') new_media_items = [{'simpleMediaItem': {'uploadToken': tok}} for tok in tokens] request_body = { 'newMediaItems': new_media_items } try: upload_response = service.mediaItems().batchCreate(body=request_body).execute() except Exception as e: print(f"批次{k}上传失败,错误信息:{e}") # 可选择将该批次token存到本地后续重试 tokens = [] # 批次上传后等待1秒,避免触发批量接口限流 time.sleep(1)
额外注意事项
- Google Photos API的上传token有效期为1小时,单批图片上传耗时不要超过1小时,你的50张一批的设置完全满足要求,不需要调整。
- 每日上传配额默认是1万张,200万张需要分批上传,可定期查看配额使用情况避免被限制。
- 已开通2T Google One存储空间不影响API配额限制,配额和存储空间是独立规则。
内容的提问来源于stack exchange,提问作者Mostafa Nakhaei
相关产品推荐
相关产品推荐

