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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 14:45:11