如何通过Drive API更改ServiceAccount上传文件的所有者
问题
我通过Python脚本调用Drive API,把电子表格里的员工数据批量上传到了Google Drive,上传成功后发现所有文件的所有者都是我创建的ServiceAccount。我尝试用脚本把所有者改成个人Gmail账号,却报错:You can't change the owner of a file owned by a service account.。现在这些文件只是共享给我,并非我拥有,要是删除或停用这个ServiceAccount,所有文件都会丢失。我需要在完成上传后停用ServiceAccount,请问怎么解决所有权变更的问题?
原因
Google Drive的权限规则限制:如果ServiceAccount和你的个人Gmail账号不属于同一个Google Workspace组织(比如你用的是免费个人Gmail),无法直接通过ServiceAccount发起所有权转移操作。
解决方案
分两种场景处理:
场景1:你使用的是Google Workspace账号(同域)
如果你的个人账号是Google Workspace账号,且ServiceAccount属于同一个域:
- 登录Google Admin控制台,找到应用 > Google Workspace > Drive和Docs > 共享设置
- 开启允许服务账号转移文件所有权的选项
- 重新运行你原来的脚本(确保
transferOwnership=True参数正确),即可完成所有权转移
场景2:你使用的是免费个人Gmail账号
这种情况无法直接转移所有权,可通过以下两种方法获取文件控制权:
方法A:将文件移动到你拥有的共享文件夹
- 先在你的个人Drive里创建一个文件夹,把这个文件夹共享给ServiceAccount的邮箱(密钥文件里的
client_email字段),并赋予编辑权限 - 用ServiceAccount的脚本把所有文件移动到这个文件夹,代码示例:
import json from googleapiclient.discovery import build from google.oauth2 import service_account # 加载ServiceAccount密钥 json_file_path = "你的ServiceAccount密钥文件路径" with open(json_file_path) as f: creds_info = json.load(f) SCOPES = ['https://www.googleapis.com/auth/drive'] creds = service_account.Credentials.from_service_account_info(creds_info, scopes=SCOPES) drive_service = build('drive', 'v3', credentials=creds) # 批量处理示例(可遍历你的文件ID列表) file_ids = ["文件ID1", "文件ID2"] target_folder_id = "你个人Drive的文件夹ID" for file_id in file_ids: try: # 移动文件到目标文件夹 drive_service.files().update( fileId=file_id, addParents=target_folder_id, # 可选:如果要移出原文件夹,添加removeParents参数 # removeParents="原文件夹ID" ).execute() print(f"文件 {file_id} 已移动成功") except Exception as e: print(f"处理文件 {file_id} 失败: {str(e)}")
移动完成后,你作为文件夹的所有者,完全控制这些文件,即使停用ServiceAccount也不会丢失。
方法B:用个人账号复制文件(获取完整所有权)
如果需要完全成为文件的所有者,可使用个人账号的OAuth2授权复制文件,复制后的文件所有者就是你:
from googleapiclient.discovery import build from google_auth_oauthlib.flow import InstalledAppFlow # 个人账号的OAuth2权限范围 SCOPES = ['https://www.googleapis.com/auth/drive'] # 加载个人账号的OAuth2客户端密钥(需在Google Cloud控制台创建) flow = InstalledAppFlow.from_client_secrets_file( "你的个人OAuth2客户端密钥.json", SCOPES ) creds = flow.run_local_server(port=0) drive_service = build('drive', 'v3', credentials=creds) # 批量复制示例 source_file_ids = ["ServiceAccount拥有的文件ID1", "文件ID2"] target_folder_id = "你个人Drive的文件夹ID" for file_id in source_file_ids: try: # 复制文件到个人Drive copied_file = drive_service.files().copy( fileId=file_id, body={"parents": [target_folder_id]} ).execute() print(f"文件已复制,新文件ID: {copied_file['id']}") except Exception as e: print(f"复制文件 {file_id} 失败: {str(e)}")
复制完成后,可删除ServiceAccount名下的原文件,彻底完成所有权转移。
注意事项
- 移动文件的方法不会生成副本,保留原文件ID;复制方法会生成新文件,原文件仍属于ServiceAccount
- 批量操作时,建议加入错误处理,避免个别文件失败导致整个流程中断
- 确保ServiceAccount对目标文件夹有编辑权限,否则无法移动文件
内容的提问来源于stack exchange,提问作者UZAIF TECH
相关产品推荐
相关产品推荐

