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

使用For循环上传照片到Google Photos时出现上传令牌无效报错

问题原因

  • 缺少单张上传请求的错误校验:当前代码直接将requests.post的返回内容解码后加入token列表,没有判断请求是否成功。如果某次上传因为网络波动、图片损坏、接口限流返回非200状态,返回的内容不是有效上传token,批量创建时就会触发400错误。
  • 文件资源泄漏:代码用open(image_path, 'rb').read()读取图片后没有主动关闭文件句柄,长时间运行会耗尽系统文件描述符,导致后续图片读取失败,上传内容为空,返回无效token。
  • 重复加载鉴权token:每次循环都读取本地pickle文件加载鉴权token,不必要的IO操作不仅拖慢速度,也有概率出现文件读取异常,导致鉴权失败,上传请求返回错误内容。

修复方案

核心优化点

  1. 单张上传后先判断响应状态码,只有200 OK的返回内容才作为有效上传token存入列表,失败的请求可以重试3次后跳过并记录日志。
  2. 鉴权token加载移到循环外部,避免重复读取本地文件。
  3. 使用with上下文管理器读取图片,自动释放文件句柄。
  4. 增加请求间隔,避免触发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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 13:18:03