使用Python递归复制Google Drive文件夹时遭遇403错误
问题:Google Drive文件夹递归复制时出现403错误
尝试用以下Python脚本递归复制Google Drive文件夹(包含文件及子文件夹),但触发403错误。凭证配置应该没问题,因为把复制函数替换成列出所有文件的函数时可以正常运行。
代码实现
import os.path from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build from googleapiclient.errors import HttpError # If modifying these scopes, delete the file token.json. SCOPES = ['https://www.googleapis.com/auth/drive'] TOKEN_PATH = 'token.json' CREDENTIALS_PATH = 'credentials.json' def get_credentials(): # Gets user credentials or prompts for authorization if needed. creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES) if os.path.exists(TOKEN_PATH) else None if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_PATH, SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for future runs with open(TOKEN_PATH, 'w') as token_file: token_file.write(creds.to_json()) return creds def copy_file(drive_service, source_file_id, destination_folder_id): # Create a copy request copy_request = { 'name': None, # Keep the same name as the original file 'parents': [destination_folder_id], } try: # Copy the file copied_file = drive_service.files().copy( fileId=source_file_id, body=copy_request ).execute() print(f'File copied with ID: {copied_file["id"]}') except Exception as e: print(f'An error occurred while copying file: {str(e)}') def copy_folder_recursive(drive_service, source_folder_id, destination_folder_id): # Copy the current folder copy_file(drive_service, source_folder_id, destination_folder_id) # List all files and subfolders in the current folder results = drive_service.files().list( q=f"'{source_folder_id}' in parents", fields="files(id, name, mimeType)").execute() # Recursively copy subfolders and their contents for item in results.get('files', []): if item['mimeType'] == 'application/vnd.google-apps.folder': copy_folder_recursive( drive_service, item['id'], copied_folder['id']) def main(): # Main function to list files and folders recursively from the root folder. creds = get_credentials() service = build('drive', 'v3', credentials=creds) # Specify the source and destination folder IDs source_folder_id = 'source_ID' destination_folder_id = 'destination_ID' # Copy the folder copy_folder_recursive(service, source_folder_id, destination_folder_id) if __name__ == '__main__': main()
错误信息
An error occurred while copying file: <HttpError 403 when requesting https://www.googleapis.com/drive/v3/files/"source_ID"/copy?alt=json returned "This file cannot be copied by the user.". Details: "[{'message': 'This file cannot be copied by the user.', 'domain': 'global', 'reason': 'cannotCopyFile'}]">
问题分析与解决方案
核心结论
这个错误不是凭证配置问题,但存在代码逻辑bug,同时核心触发原因是文件/权限限制。
1. 403错误的根本原因
- 错误码
cannotCopyFile明确说明:当前授权用户没有复制该文件/文件夹的权限,或者文件本身受限制:- 源文件是他人共享的只读权限文件,只读权限无法执行复制操作;
- 共享文件时被设置了禁止下载、打印和复制(Google原生文件如Docs/Sheets的共享权限选项);
- Google Workspace账号受管理员限制,禁止复制外部共享文件;
- 文件是版权保护内容,无法被复制。
- 你能正常列出文件,说明凭证拥有读取权限,但复制需要更高的权限(如编辑权限、所有者权限),所以不是凭证配置的问题。
2. 代码中的逻辑bug
在copy_folder_recursive函数中,你尝试使用copied_folder['id']作为子文件夹的目标ID,但这个变量从未定义:
copy_file函数没有返回复制后的文件信息;- 调用
copy_file后没有保存返回值,导致后续递归时找不到copied_folder变量(会引发NameError,只是当前403错误先出现)。
修复后的代码片段:
def copy_file(drive_service, source_file_id, destination_folder_id): copy_request = { 'name': None, # 保留原文件名 'parents': [destination_folder_id], } try: copied_file = drive_service.files().copy(fileId=source_file_id, body=copy_request).execute() print(f'File copied with ID: {copied_file["id"]}') return copied_file # 新增返回复制后的文件信息 except Exception as e: print(f'An error occurred while copying file: {str(e)}') return None # 出错时返回None def copy_folder_recursive(drive_service, source_folder_id, destination_folder_id): # 复制当前文件夹并保存副本信息 copied_folder = copy_file(drive_service, source_folder_id, destination_folder_id) if not copied_folder: return # 文件夹复制失败时终止递归 # 列出当前文件夹下的所有文件和子文件夹 results = drive_service.files().list( q=f"'{source_folder_id}' in parents", fields="files(id, name, mimeType)").execute() # 递归复制子文件夹及其内容 for item in results.get('files', []): if item['mimeType'] == 'application/vnd.google-apps.folder': copy_folder_recursive( drive_service, item['id'], copied_folder['id'])
3. 解决403错误的步骤
- 检查源文件夹/文件的权限:确保你拥有编辑权限,而非只读;
- 查看共享设置:对于Google原生文件,确认共享者没有勾选“禁止下载、打印和复制”;
- 企业账号联系管理员:如果是Workspace账号,确认没有限制外部文件复制的政策;
- 测试单个文件复制:尝试复制一个你自己创建的文件,验证权限是否正常。
内容的提问来源于stack exchange,提问作者x0100
相关产品推荐
相关产品推荐

