Python Requests实现带进度条的Google Drive指定文件夹上传故障排查
修复Google Drive文件上传到指定文件夹的问题
我用Python Requests写了不依赖Google Drive官方SDK的文件上传代码,带进度条,但文件无法上传到指定文件夹,调整后仍未解决,求修复方案。
原代码
import os import sys import json import requests import collections from tqdm import tqdm import requests_toolbelt from requests.exceptions import JSONDecodeError class ProgressBar(tqdm): def update_to(self, n: int) -> None: self.update(n - self.n) def upload_file(access_token:str, filename:str, filedirectory:str, folder_id: str): metadata = { "name": filename, "parents": [{"id": folder_id}] } session = requests.session() with open(filedirectory, "rb") as fp: files = collections.OrderedDict(data=("metadata", json.dumps(metadata), "application/json"), file=fp) encoder = requests_toolbelt.MultipartEncoder(files) with ProgressBar( total=encoder.len, unit="B", unit_scale=True, unit_divisor=1024, miniters=1, file=sys.stdout, ) as bar: monitor = requests_toolbelt.MultipartEncoderMonitor( encoder, lambda monitor: bar.update_to(monitor.bytes_read) ) r = session.post( "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart", data=monitor, allow_redirects=False, json=metadata, headers={"Authorization": "Bearer " + access_token, "Content-Type": monitor.content_type}, ) try: resp = r.json() print(resp) except JSONDecodeError: sys.exit(r.text) upload_file(access_token, filename, filedirectory, "12345asdfghj")
问题分析
- 元数据格式错误:Google Drive API要求
parents字段是文件夹ID的数组,而非包含id键的对象数组,正确格式应为[folder_id]。 - 请求参数冲突:同时传递
data=monitor(multipart格式数据)和json=metadata会导致请求内容混乱,multipart数据中已包含元信息,无需额外传递json参数。 - Multipart字段命名问题:
OrderedDict中的键名data不符合API要求,应直接使用metadata作为字段名,确保API能正确识别元数据部分。
修复后的代码
import os import sys import json import requests import collections from tqdm import tqdm import requests_toolbelt from requests.exceptions import JSONDecodeError class ProgressBar(tqdm): def update_to(self, n: int) -> None: self.update(n - self.n) def upload_file(access_token: str, filename: str, filedirectory: str, folder_id: str): # 修正parents字段格式:直接传入文件夹ID数组 metadata = { "name": filename, "parents": [folder_id] } session = requests.session() with open(filedirectory, "rb") as fp: # 修正Multipart字段命名,确保metadata字段被正确识别 files = collections.OrderedDict([ ("metadata", (None, json.dumps(metadata), "application/json")), ("file", (filename, fp, "application/octet-stream")) ]) encoder = requests_toolbelt.MultipartEncoder(files) with ProgressBar( total=encoder.len, unit="B", unit_scale=True, unit_divisor=1024, miniters=1, file=sys.stdout, ) as bar: monitor = requests_toolbelt.MultipartEncoderMonitor( encoder, lambda monitor: bar.update_to(monitor.bytes_read) ) # 移除冲突的json参数,仅保留multipart数据和正确的请求头 r = session.post( "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart", data=monitor, allow_redirects=False, headers={ "Authorization": f"Bearer {access_token}", "Content-Type": monitor.content_type }, ) try: resp = r.json() if r.status_code == 200: print(f"文件上传成功,文件ID:{resp['id']}") else: print(f"上传失败:{resp}") except JSONDecodeError: sys.exit(f"请求错误:{r.text}") # 替换为实际的access_token、filename、文件路径和目标文件夹ID upload_file("your_access_token", "example.txt", "/path/to/example.txt", "12345asdfghj")
补充说明
- 确保你的
access_token拥有https://www.googleapis.com/auth/drive的权限,否则无法修改文件的父文件夹。 - 修复后的代码中,Multipart的
metadata部分使用(None, json.dumps(metadata), "application/json"),其中None表示该部分没有文件名,符合API对元数据部分的要求。 - 给
file部分指定了文件名和正确的MIME类型,避免API识别文件类型出错。
内容的提问来源于stack exchange,提问作者jak bin
相关产品推荐
相关产品推荐

