Google Drive API with Python 不允许下载文件,尽管添加了正确的范围



我已经按照谷歌提供的快速入门来使用Python,并且我已经使用了谷歌提供的适当范围从驱动器 https://www.googleapis.com/auth/drive.readonly 下载文件,但我不断收到以下错误:

googleapiclient.errors.HttpError: https://www.googleapis.com/drive/v3/files/1RWpLGCWldcJyVqa0tIVlScg60ExEtcNIvJ7R9M8DuhM?alt=media 返回"只能下载包含二进制内容的文件。使用导出 与谷歌文档文件。

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

我可以读取驱动器上的文件,但尽管我尽了最大努力,但我似乎无法从驱动器下载特定的电子表格。以下是我的代码(编辑的文件路径和一些注释(,用于通过 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提供的内容下载文件的功能(编辑的文件路径和一些注释(:

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 或任何其他凭据,但如果您需要更多信息,请告诉我!

  • 您想使用 google-api-python-client 和 python 下载 Google 文档(在您的情况下,它是电子表格(。
  • 您想知道Only files with binary content can be downloaded. Use Export with Google Docs files.错误的原因
  • 您已经能够使用云端硬盘 API。

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

修改点:

  • 当通过get_media方法下载Google文档文件时,会发生此类错误。
    • 对于get_media方法,可以下载除Google文档(电子表格,文档,幻灯片等(以外的文件。
  • 当您想下载Google文档文件时,请使用export_media方法。
    • 在这种情况下,由于谷歌端的规范,无法下载原始的谷歌文档。因此,请将其转换为其他格式。例如,在电子表格的情况下,它是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')
  • 在这种情况下,谷歌电子表格将下载为Excel文件。如果要下载为CSV,请将mimeType修改为text/csv

注意:

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

引用:

  • 下载文件
  • 文件:获取
  • 文件:导出

如果我误解了你的问题,这不是你想要的方向,我很抱歉。

添加:

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

我正在使用它,它适用于以下库:

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

最新更新