当前位置: 首页 > 知识库问答 >
问题:

使用服务帐户凭据的GDrive导出失败,404

傅元龙
2023-03-14

我有一个使用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服务帐户示例

我的新服务帐户脚本执行完全相同的操作,如下所示-

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错误有什么想法吗?

共有2个答案

杨经武
2023-03-14

在打电话之前,先整理一下文件。列出以查看服务帐户可以访问哪些文件。整理文件。获取服务帐户无权访问的文件将导致文件未找到错误。记住,服务帐户不是你的,它有自己的google drive帐户。您想要访问的任何文件都需要上传到其帐户或与服务帐户共享。

如果你能找到文件。列表失败,那么它会向我建议授权有问题,你应该确保服务帐户可以访问客户端文件,可能是它找不到的文件。

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

  • 向该目录添加文件可能会或可能不会给服务号自动访问它们的权限是一种痛苦,您可能还需要与服务号共享文件。
  • 记得让服务号在上传文件时授予您的个人帐户权限,它将是所有者。
汪建白
2023-03-14

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

与处理任何文件一样,您需要为用户提供查看该文件的显式权限。由于服务账户对您来说是一个独立的实体,这也适用于他们。

使用文件共享设置(只需在驱动器用户界面中右键单击文件并点击共享),为服务帐户的电子邮件地址授予正确的权限(读/写)。服务帐户的电子邮件地址如下所示:

service-account-name@project-id.iam.gserviceaccount.com
 类似资料:
  • 我正在构建一个需要读取普通Gmail收件箱(不是域的一部分)的Web服务。 代码: 错误: 我看不出这有什么原因不起作用,但读完这篇文章后,你似乎不能在个人@gmail帐户上使用服务帐户凭据。有谁知道这是真的还是我做错了什么? 感谢您的帮助! 更新 如果我将更改为,我可以查看邮件,但无法修改标签,这是我的要求。

  • 因此,我正在尝试在我的本地主机上获取服务应用程序凭据,并且遇到了一些问题。我创建并下载了json密钥,我想保护它们,而不是让它们变成纯文本。 我想知道最好的方法。我有这个代码: 这里的问题是我的JSON文件在我的存储库中以纯文本形式公开。

  • 我正在尝试在 Go 应用引擎部署上使用具有域范围委派 (DwD) 的服务帐户。 我已按照使用 Google 应用程序默认凭据的步骤将服务帐户与应用引擎配合使用。 我让代码在我的开发计算机上本地运行,但我被困在从我的域中检索实际数据。 我用的是Admin SDK。在“向您的服务帐户授予域范围的权限”一节中,它说我的“服务帐户需要模拟其中一个用户来访问Admin SDK Directory API”。

  • 有三种类型的google apiclient_id: 1. Web应用程序 2.服务帐户 3.已安装的应用程序 我用了基于 oauth2 客户端成功安装应用程序,但在 2 上失败。我想使用 oauth2.0 凭据访问我自己的 gmail 。 我得到了一个与问题相同的例外。我在尝试将添加到凭据时遇到另一个异常: 我正在尝试解决问题,使用< code >凭据而不使用< code>sub: 尝试将与一起

  • 为了访问GMail API(并将呼叫拟人化),我使用了一个服务帐户(从谷歌云平台创建)。我的json文件看起来像这样 我还使用oAuth2client库使其更容易,但我找不到创建凭据然后指定范围和委托帐户的方法。 我试过了 但是我得到了一个错误,因为它需要一个PKCS-8密钥。 我该怎么做?(如果有帮助,我的代码在应用程序引擎 Flex 上运行) 谢啦

  • 问题内容: 我正在尝试在具有Go的App Engine部署中使用具有域范围委托(DwD)的服务帐户。 我已经按照步骤使用Google应用程序默认凭据在App Engine中使用服务帐户。 我的代码在我的开发机器上本地运行,但是我一直坚持从域中检索实际数据。 我正在使用Admin SDK。在“将域范围的权限委派给您的服务帐户”部分下,它说我“服务帐户需要模拟其中一个用户来访问Admin SDK Di