【问题标题】:GDrive export using Service Account creds fails with 404使用服务帐户凭据导出 GDrive 失败并显示 404
【发布时间】:2021-02-17 00:15:02
【问题描述】:

我有一个脚本可以使用 OAuth 客户端从 GDrive 文件中导出文本,效果很好 -

import googleapiclient.discovery as google

from apiclient.http import MediaIoBaseDownload

from google_auth_oauthlib.flow import InstalledAppFlow

from google.auth.transport.requests import Request

import datetime, io, os, pickle

Scopes=" ".join(['https://www.googleapis.com/auth/drive.file',
                 'https://www.googleapis.com/auth/drive.metadata',
                 'https://www.googleapis.com/auth/drive.readonly'])

TokenFile="token.pickle"

def init_creds(clientfile,
               scopes,
               tokenfile=TokenFile):            
    token=None
    if os.path.exists(tokenfile):
        with open(tokenfile, 'rb') as f:
            token=pickle.load(f)            
    if (not token or
        not token.valid or
        token.expiry < datetime.datetime.utcnow()):    
        if (token and
            token.expired and
            token.refresh_token):
            token.refresh(Request())
        else:
            flow=InstalledAppFlow.from_client_secrets_file(clientfile, scopes)
            token=flow.run_local_server(port=0)
        with open(tokenfile, 'wb') as f:
            pickle.dump(token, f)
    return token

def export_text(id,
                clientfile,
                scopes=Scopes):
    creds=init_creds(clientfile=clientfile,
                     scopes=scopes)
    service=google.build('drive', 'v3', credentials=creds)
    request=service.files().export_media(fileId=id,
                                         mimeType='text/plain')
    buf=io.BytesIO()
    downloader, done = MediaIoBaseDownload(buf, request), False
    while done is False:
        status, done = downloader.next_chunk()
        destfilename="tmp/%s.txt" % id
    return buf.getvalue().decode("utf-8")

if __name__=='__main__':
    print (export_text(id="#{redacted}"
                       clientfile="/path/to/oath/client.json"))

但是每次都必须通过 OAuth 流程很痛苦,因为只有我使用脚本,所以我想简化事情并改用服务帐户,从这篇文章开始 -

Google Drive API Python Service Account Example

我的新服务帐户脚本,做的一模一样,如下 -

import googleapiclient.discovery as google

from oauth2client.service_account import ServiceAccountCredentials

from apiclient.http import MediaIoBaseDownload

import io

Scopes=" ".join(['https://www.googleapis.com/auth/drive.file',
                 'https://www.googleapis.com/auth/drive.metadata',
                 'https://www.googleapis.com/auth/drive.readonly'])

def export_text(id,
                clientfile,
                scopes=Scopes):
    creds=ServiceAccountCredentials.from_json_keyfile_name(clientfile,
                                                           scopes)
    service=google.build('drive', 'v3', credentials=creds)
    request=service.files().export_media(fileId=id,
                                         mimeType='text/plain')
    buf=io.BytesIO()
    downloader, done = MediaIoBaseDownload(buf, request), False
    while done is False:
        status, done = downloader.next_chunk()
        destfilename="tmp/%s.txt" % id
    return buf.getvalue().decode("utf-8")

if __name__=='__main__':
    print (export_text(id="#{redacted}",
                       clientfile="path/to/service/account.json"))

但是当我为相同的 id 运行它时,我得到以下信息 -

googleapiclient.errors.HttpError: <HttpError 404 when requesting https://www.googleapis.com/drive/v3/files/#{redacted}/export?mimeType=text%2Fplain&alt=media returned "File not found: #{redacted}.">

感觉就像服务帐户脚本正在通过身份验证步骤(即服务帐户凭据没问题),但在尝试获取文件时失败 - 很奇怪,因为我可以使用 OAuth 版本很好地获取它:/

鉴于 OAuth 客户端版本显然适用于相同的 id,对于可能导致服务帐户版本中出现此 404 错误的任何想法?

【问题讨论】:

  • 问题: 1. 您是否拥有该文件? 2.您是否与服务帐户共享文件? 3. 您是在使用@gmail 还是在 Google Workspace 域中? 4. 如果您在域中,是否设置了域范围的委派?
  • 1) 是 2) 否 - 您如何执行该步骤?认为这可能是问题 3) gmail 4) 否 5) 谢谢你
  • 您使用通常共享文件的方法与服务帐户共享文件 - 只有您必须与服务帐户的电子邮件地址共享文件。格式为service-account-name@project-id.iam.gserviceaccount.com

标签: python google-api google-drive-api google-api-python-client service-accounts


【解决方案1】:

在拨打电话之前,请执行 File.list 以查看服务帐户可以访问哪些文件。对服务帐户无权访问的文件执行 file.get 将导致找不到文件错误。请记住,服务帐户不是您,它有自己的 google drive 帐户。您要访问的任何文件都需要上传到其帐户或与服务帐户共享。

如果 file.list 失败,那么它会提示我授权有问题,您应该确保服务帐户可以访问客户端文件,也许是它无法找到的那个文件。

授予服务帐号访问权限

在您的个人 google drive 帐户上创建一个目录。以服务帐户电子邮件地址为例,它可以在您下载的密钥文件中找到,其中有一个 @。然后与服务帐户共享您驱动器帐户上的该目录,就像您与任何其他用户共享一样。

  • 将文件添加到该目录可能会或可能不会自动授予服务帐户对它们的访问权限,这很麻烦,您可能还需要与服务帐户共享文件。
  • 请记住让服务帐户在上传文件时授予您的个人帐户对文件的权限,该文件将成为所有者。

【讨论】:

  • “记住服务帐户不是你” - 认为这是问题所在 - 没有意识到服务帐户不会自动访问我的驱动器文件 - 我如何才能获得许可?谢谢
  • 不要感觉不好,这通常是问题所在。 ?我已经对问题进行了更新。
【解决方案2】:

答案:

您需要与服务帐户共享您的文件。

更多信息:

就像处理任何文件一样,您需要给用户明确的权限才能看到它。由于服务帐户对您来说是一个单独的实体,因此这也适用于他们。

使用文件共享设置(您可以在云端硬盘 UI 中执行此操作,方法是右键单击文件并点击 Share),为服务帐户的电子邮件地址提供正确的权限(读/写)。服务帐号的电子邮件地址格式为:

service-account-name@project-id.iam.gserviceaccount.com

【讨论】:

  • 这个步骤可以通过 API 以编程方式完成吗?
  • 确实可以!您需要创建一个权限并将其添加到文件中。查看链接here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-31
  • 1970-01-01
  • 2023-01-12
  • 2016-03-03
  • 2010-11-07
  • 2014-06-23
  • 1970-01-01
相关资源
最近更新 更多