尽管添加了正确的作用域,但带有Python的Google Drive API不允许文件下载

时间:2019-12-06 11:40:18

标签: python google-api google-drive-api

我遵循Google给出的quickstart使用Python,并且使用了Google给出的适当范围从云端硬盘https://www.googleapis.com/auth/drive.readonly下载文件,但是我不断遇到错误:

  

googleapiclient.errors.HttpError:https://www.googleapis.com/drive/v3/files/1RWpLGCWldcJyVqa0tIVlScg60ExEtcNIvJ7R9M8DuhM?alt=media   返回“只能下载具有二进制内容的文件。请使用导出   使用Google Docs文件。”

当我尝试运行代码来下载文件时。

我可以读取驱动器上的哪些文件,但是尽管我已尽力而为,但似乎无法从驱动器下载特定的电子表格。这是我的以下代码(经过编辑的文件路径和一些注释),用于通过API建立连接:

def gsuite_connect():

    file_path = 'OMITTED/Loading'

    # Get what permissions the user (using the API) will need. This as been set to high level
    # access by default
    scopes = ['https://www.googleapis.com/auth/drive.readonly']
    
    # Access the tokens for G Suite to access the Drive. Ensure that if this file previous exists,
    # that it is in the current working directory
    store = file.Storage(os.path.join(file_path, 'storage.json'))
    
    # Access the credentials for the Drive API
    creds = store.get()
    
    if not creds or creds.invalid:
        print("\nUsing credentials found in client_id(secret).json")
        flow = client.flow_from_clientsecrets(os.path.join(file_path, 'client_id.json'), scopes)
        creds = tools.run_flow(flow, store)
    
    http = creds.authorize(Http())
    drive = discovery.build('drive', 'v3', http=http)
    sheets = discovery.build('sheets', 'v4', http=http)
    
    return drive, sheets

这是我用来根据Google provides下载文件的功能(已编辑的文件路径和一些注释):

    def get_datalog(self):

        dir_path = 'OMITTED/Downloads'
        fname = "'FILENAME'"
        files = self.drive.files().list(q="name = {}".format(fname),
                                        fields="nextPageToken, files(id, name)").execute()
        items = files.get('files', [])

        # Error checking and subsequent downloading if file successfully found
        if not items:
            exit()
        else:

            # Change into the desired directory for storing the file and download file based on the
            # retrieved ID
            os.chdir(dir_path)
            file_id = items[0]['id']

            # Request download service
            request = self.drive.files().get_media(fileId=file_id)

            fh = io.FileIO(fname, mode='w')
            downloader = MediaIoBaseDownload(fh, request)
            done = False
            while done is False:
                status, done = downloader.next_chunk()
                print("Download %d%%." % int(status.progress() * 100))

            # Return the file path
            return os.path.join(dir_path, fname)

我们将不胜感激!我不想显示敏感文件,例如client_id.json或任何其他凭证,但是如果需要更多信息,请告诉我!

2 个答案:

答案 0 :(得分:2)

  • 您想使用带有python的google-api-python-client下载Google Docs(在您的情况下是Spreadsheet。)
  • 您想知道Only files with binary content can be downloaded. Use Export with Google Docs files.错误的原因
  • 您已经可以使用Drive API。

如果我的理解正确,那么这个答案如何?

修改点:

  • 通过get_media方法下载Google Docs文件时,会发生此类错误。
    • 对于get_media方法,可以下载Google Docs之外的文件(电子表格,文档,幻灯片等)。
  • 要下载Google Docs文件时,请使用export_media方法。
    • 在这种情况下,由于Google方面的规范,无法下载原始Google文档。因此,请转换为其他格式。例如,对于电子表格,它是Excel格式,CSV格式等等。

修改后的脚本:

为了避免该问题,如何进行以下修改?

从:
request = self.drive.files().get_media(fileId=file_id)
至:
request = self.drive.files().export_media(fileId=file_id, mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  • 在这种情况下,Google Spreadsheet是作为Excel文件下载的。如果要以CSV格式下载,请将mimeType修改为text/csv

注意:

  • 在这种情况下,它假设您要下载的Google Docs文件是您的文件或公开共享的文件。

参考文献:

如果我误解了您的问题,而这不是您想要的方向,我深表歉意。

已添加:

关于更改访问令牌范围的方法,请重命名或删除脚本中的storage.json文件,然后再次运行该脚本。这样,您可以重新授权新作用域,并创建包含令牌的新文件。您可以在新的作用域中使用访问令牌。

答案 1 :(得分:0)

我正在使用它,并且可以在以下库中使用:

google-auth-oauthlib==0.4.1
google-api-python-client
google-auth-httplib2

这是我正在使用的代码段:

from apiclient import errors
from googleapiclient.http import MediaIoBaseDownload
from googleapiclient.discovery import build

def download_google_document_from_drive(self, file_id):
    try:

        request = self.service.files().get_media(fileId=file_id)
        fh = io.BytesIO()
        downloader = MediaIoBaseDownload(fh, request)
        done = False
        while done is False:
            status, done = downloader.next_chunk()
            print('Download %d%%.' % int(status.progress() * 100))
        return fh
    except Exception as e:
        print('Error downloading file from Google Drive: %s' % e)

您可以将文件流写入文件:

import xlrd
workbook = xlrd.open_workbook(file_contents=fh.getvalue())

至于作用域,我使用以下代码段:

def __init__(self):
  self.service = build('drive', 'v3',
                    credentials=self._service_account_credentials())

def _service_account_credentials(self.):
   service_account_key_path = os.getenv('GOOGLE_APPLICATION_CREDENTIALS')

   credentials = service_account.Credentials.from_service_account_file(
     service_account_key_path)
   scoped_credentials = credentials.with_scopes(
     ['https://www.googleapis.com/oauth2/v4/token'])
   signer_email = scoped_credentials.service_account_email
   signer = scoped_credentials.signer

   credentials = google.oauth2.service_account.Credentials(
     signer,
     signer_email,
     token_uri='https://www.googleapis.com/oauth2/v4/token'
   )
   return credentials