如何使用Python和Drive API v3从Google Drive下载文件

9

我尝试使用Python脚本从Google Drive下载文件到我的本地系统,但在运行Python脚本时遇到了“禁止”问题。脚本如下:

import requests

url = "https://www.googleapis.com/drive/v3/files/1wPxpQwvEEOu9whmVVJA9PzGPM2XvZvhj?alt=media&export=download"

querystring = {"alt":"media","export":"download"}

headers = {
    'Authorization': "Bearer TOKEN",

    'Host': "www.googleapis.com",
    'Accept-Encoding': "gzip, deflate",
    'Connection': "keep-alive",
    }

response = requests.request("GET", url, headers=headers, params=querystring)

print(response.url)
#
import wget
import os
from os.path import expanduser


myhome = expanduser("/home/sunarcgautam/Music")
### set working dir
os.chdir(myhome)

url = "https://www.googleapis.com/drive/v3/files/1wPxpQwvEEOu9whmVVJA9PzGPM2XvZvhj?alt=media&export=download"
print('downloading ...')
wget.download(response.url)

在这个脚本中,我遇到了被禁止的问题。在脚本中我做错了什么吗?
我还尝试了另一个我在 Google 开发者页面上找到的脚本,如下所示:
import auth
import httplib2
SCOPES = "https://www.googleapis.com/auth/drive.scripts"
CLIENT_SECRET_FILE = "client_secret.json"
APPLICATION_NAME = "test_Download"
authInst = auth.auth(SCOPES, CLIENT_SECRET_FILE, APPLICATION_NAME)
credentials = authInst.getCredentials()
http = credentials.authorize(httplib2.Http())
drive_serivce = discovery.build('drive', 'v3', http=http)

file_id = '1Af6vN0uXj8_qgqac6f23QSAiKYCTu9cA'
request = drive_serivce.files().export_media(fileId=file_id,
                                             mimeType='application/pdf')
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))

这个脚本给了我一个URL不匹配的错误
那么在Google控制台凭证中,需要提供什么样的重定向URL?或者有其他解决方案吗?我是否需要在两个脚本中都从Google授权我的Google控制台应用程序?如果是这样的话,授权应用程序的过程是什么,因为我没有找到任何相关文档。

请使用Google的发现API for Python:https://developers.google.com/drive/api/v3/quickstart/python - Ramon Medeiros
https://developers.google.com/drive/api/v3/manage-downloads - Ramon Medeiros
@Aerials 是的,我已经在API控制台中创建了项目。 - Gautam Bothra
您能提供找到第二个脚本来源的链接吗?并且请提供 auth 模块,因为这里没有显示。谢谢。 - Aerials
让我们在聊天中继续这个讨论 - Gautam Bothra
显示剩余7条评论
1个回答

22

要向Google APIs发出请求,工作流程本质上如下:

  1. 前往开发者控制台,如果没有登录,请登录。
  2. 创建一个Cloud平台项目。
  3. 为您的项目启用您想要在项目应用程序中使用的API(例如:Google Drive API)。
  4. 创建并下载允许您的应用获取使用启用的API的授权的OAuth 2.0客户端ID凭据。
  5. 转到OAuth同意屏幕,单击enter image description here,并使用enter image description here按钮添加您的范围 (范围:https://www.googleapis.com/auth/drive.readonly适用于您)。根据您的需求选择内部/外部,并暂时忽略任何警告。
  6. 为了获取有效的令牌以进行API请求,应用程序将通过OAuth流程接收授权令牌。(因为它需要同意)
  7. 在OAuth流程期间,用户将被重定向到您的OAuth同意屏幕,在那里他/她将被要求批准或拒绝访问您的应用程序请求的范围。
  8. 如果同意,则您的应用程序将收到授权令牌。
  9. 在请求中传递您的授权API端点的令牌。[2]
  10. 构建一个Drive服务来进行API请求(您将需要有效的令牌)[1]

注意:

Drive API v3的文件资源的可用方法在此处

当使用Python Google APIs客户端时,您可以按照Google APIs Python客户端文档使用export_media()get_media()


重要提示:

还要检查您使用的范围是否实际允许您执行所需操作(从用户的Drive下载文件),并相应设置它。目前,您的目标具有不正确的范围。请参见OAuth 2.0 API Scopes


示例代码引用:

  1. 构建Drive服务:
import google_auth_oauthlib.flow
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
 
 
class Auth:
 
    def __init__(self, client_secret_filename, scopes):
        self.client_secret = client_secret_filename
        self.scopes = scopes
        self.flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(self.client_secret, self.scopes)
        self.flow.redirect_uri = 'http://localhost:8080/'
        self.creds = None
 
    def get_credentials(self):
        flow = InstalledAppFlow.from_client_secrets_file(self.client_secret, self.scopes)
        self.creds = flow.run_local_server(port=8080)
        return self.creds

 
# The scope you app will use. 
# (NEEDS to be among the enabled in your OAuth consent screen)
SCOPES = "https://www.googleapis.com/auth/drive.readonly"
CLIENT_SECRET_FILE = "credentials.json"
 
credentials = Auth(client_secret_filename=CLIENT_SECRET_FILE, scopes=SCOPES).get_credentials()
 
drive_service = build('drive', 'v3', credentials=credentials)
  1. 发出导出或获取文件的请求
request = drive_service.files().export(fileId=file_id, mimeType='application/pdf')

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))

# The file has been downloaded into RAM, now save it in a file
fh.seek(0)
with open('your_filename.pdf', 'wb') as f:
    shutil.copyfileobj(fh, f, length=131072)

2
请阅读Google APIs Python客户端文档,这里记录了get_media()的相关信息。 - Aerials
谢谢您指引我正确的方向。Export是要使用的API。 - LukeSavefrogs
@Aerials 为什么在 copyfileodj 函数中需要将长度设置为 131072? - Tyler Houssian
嗨,不是的。那是我选择的缓冲区大小。 - Aerials
@Aerials 可以将PDF文件写入Google Drive账户,而不是Python脚本所在的位置吗? - user3422637
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接