Экспорт GDrive с использованием кредитов сервисного аккаунта завершился неудачно с ошибкой 404

У меня есть сценарий для экспорта текста из файла GDrive с помощью клиента OAuth, который отлично работает -

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, и, поскольку только я использую сценарий, я хочу упростить вещи и вместо этого использовать учетную запись службы, следуя этому сообщению -

Пример учетной записи службы Python Google Drive API

Мой новый скрипт учетной записи службы, делающий то же самое, выглядит следующим образом:

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:/

Любые мысли о том, что может вызвать эту ошибку 404 в версии учетной записи службы, учитывая, что версия клиента OAuth явно работает для того же id?

TIA.

2 ответа

Решение

Ответ:

Вам необходимо поделиться своим файлом с учетной записью службы.

Больше информации:

Как и в случае с любым файлом, вам необходимо предоставить пользователю явные разрешения, чтобы иметь возможность его видеть. Поскольку учетная запись службы - это отдельное право для вас, это также относится и к ним.

Используя настройки общего доступа к файлам (вы можете просто сделать это в пользовательском интерфейсе Диска, щелкнув файл правой кнопкой мыши и выбрав Share), дайте адресу электронной почты учетной записи службы правильное разрешение (чтение / запись). Электронный адрес учетной записи службы имеет следующий вид:

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

Надеюсь, это поможет вам!

Перед тем как позвонить, создайте File.list, чтобы увидеть, к каким файлам у учетной записи службы есть доступ. Выполнение file.get для файла, к которому у учетной записи службы нет доступа, приведет к ошибке "файл не найден". Помните, что учетная запись службы - это не вы, у нее есть собственная учетная запись на Google Диске. Любые файлы, к которым вы хотите получить доступ, должны быть загружены в его учетную запись или переданы учетной записи службы.

Если файл file.list не работает, это может предположить, что с авторизацией что-то не так, и вы должны убедиться, что учетная запись службы имеет доступ к клиентскому файлу, возможно, это тот файл, который он не может найти.

Предоставление доступа к сервисному аккаунту

Создайте каталог в своей личной учетной записи Google Drive. Возьмите адрес электронной почты учетной записи службы, он находится в загруженном вами ключевом файле, в нем есть @. Затем поделитесь этим каталогом в своей учетной записи на диске с учетной записью службы, как если бы вы делились с любым другим пользователем.

  • Добавление файлов в этот каталог может предоставить или не предоставить учетной записи службы автоматический доступ к ним с разрешениями - это проблема, которая может потребоваться для совместного использования файла с учетной записью службы.
  • Не забудьте, что сервисная учетная запись предоставит вашей личной учетной записи разрешения на файл, когда он загружает его, он будет владельцем.
Другие вопросы по тегам