【发布时间】:2017-08-01 05:30:07
【问题描述】:
这是我在服务器端测试从谷歌驱动器导出文件的代码。
import logging
from flask import Flask, render_template, request
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload
from oauth2client.client import AccessTokenCredentials
import httplib2
import io
app = Flask(__name__)
@app.route('/gdrive/selectcallback')
def userselectioncallback():
print "In user selection callback... "
code = request.args.get('user_token')
fileId = request.args.get('fileId')
credentials = AccessTokenCredentials(code,
'my-user-agent/1.0')
http = httplib2.Http()
http_auth = credentials.authorize(http)
drive_service = build('drive', 'v3', http=http_auth)
drive_request = drive_service.files().export(
fileId=fileId,
mimeType='application/pdf')
fh = io.FileIO('test.pdf', 'wb')
downloader = MediaIoBaseDownload(fh, drive_request)
done = False
while done is False:
status, done = downloader.next_chunk()
print "Download %d%%." % int(status.progress() * 100)
return code
if __name__ == '__main__':
# This is used when running locally. Gunicorn is used to run the
# application on Google App Engine. See entrypoint in app.yaml.
app.run(host='127.0.0.1', port=8090, debug=True)
在 Web 客户端,一旦用户从文件选择器中选择了一个文件,javascript 前端将使用令牌和文件 ID 调用上述 python 代码中的/gdrive/selectcallback。
例如,令牌看起来像这样:ya29.Glu5BG-LQJFqZ-e4uImMSxz-14iS41jVLfXk6rVKvAPjylCwhUh98ZJk1iIC5Eb49pTfflGnU6qE7uzK44AYr0Wn79QMUkF368WFaYrhidrvpVjcsJSZ9P1M8VU6,文件 ID 看起来像这样 1ON9kGyb02TFCygy8jeIYyo2BKj5SzKgAP0xi5Rm08D4
这是相关的前端代码(在coffeescript中):
pickerCallback = () ->
view = new google.picker.View(google.picker.ViewId.PRESENTATIONS)
picker = new google.picker.PickerBuilder()
.enableFeature(google.picker.Feature.NAV_HIDDEN)
.setAppId('zeetings')
.setOAuthToken(oauthToken)
.addView(view)
.setDeveloperKey(env['googleapi-client'].apiKey)
.setCallback(selectCallback) # The callback calls the python backend
.build()
picker.setVisible true
selectCallback = (data) ->
if data.action is google.picker.Action.PICKED
fileId = data.docs[0].id
fileSelectedCallback(fileId, oauthToken) if fileSelectedCallback
根据调试信息,我的 python 代码发出这两个 https 调用:
2017-09-01 11:32:38,810 pid 260 tid 140546358265600 信息
正在请求的发现 URL:GET https://www.googleapis.com/discovery/v1/apis/drive/v3/rest2017-09-01 11:32:39,009 pid 260 tid 140546358265600 INFO 发现 URL 被请求:GET https://www.googleapis.com/drive/v3/files/1ON9kGyb02TFCygy8jeIYyo2BKj5SzKgAP0xi4Rm08D4/export?mimeType=application%2Fpdf
如果我直接在浏览器中使用第二个 url,我会收到以下错误:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
(我不认为上面的错误信息实际上反映了根本原因。更有可能是由于调用未在我的浏览器中进行身份验证。)
我怀疑我必须使用 google-auth 库 (https://google-auth.readthedocs.io/en/latest/user-guide.html#making-authenticated-requests),但我不确定如何将 google-auth 与上面的 python 代码结合起来。我想我可以通过
from google.oauth2 import service_account
credentials = service_account.Credentials.from_service_account_file(
'/path/to/key.json')
但是在这之后我应该如何处理credentials?我是否用它来完全替换credentials = AccessTokenCredentials(code,'my-user-agent/1.0')?
附:
根据@Tanaike 的建议,我尝试直接使用 API url。这是我得到的结果:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "fileNotDownloadable",
"message": "Only files with binary content can be downloaded. Use Export with Google Docs files.",
"locationType": "parameter",
"location": "alt"
}
],
"code": 403,
"message": "Only files with binary content can be downloaded. Use Export with Google Docs files."
}
}
这似乎是一个 v3 API 问题。如果我切换到 v2 并使用 downloadUrl 链接,我可以下载 pdf 格式的文件。
【问题讨论】:
-
您从导出 API 收到什么错误消息?通过 API 资源管理器导出似乎工作正常
-
问题中提到的特定幻灯片发生了这种情况(也提供了一个链接)。 “下载 0%”被打印了很多次,直到最后一个 500 被捕获
-
您可能需要检查报告为issue 的驱动器 API 返回错误 500。目前尚不清楚它现在是否适用于 v3,因为报告仅确认它在 v2 中有效。您可能想关注该问题,然后评论/创建一个新问题。希望对您有所帮助
-
当它找到刷新令牌和文件ID时,您可以使用Drive API。在您的脚本中,可以找到文件 ID。我想确认刷新令牌。
code = request.args.get('user_token')是什么?看来这可能是刷新令牌。如果那是刷新令牌,我可以问你刷新令牌中包含的范围吗?而且,您是否已经在 API 控制台启用了 Drive API? -
@Tanaike 我在问题中添加了一些前端代码,只是发现我的咖啡脚本代码存在问题:我可能将 oauth2 令牌而不是文件访问代码传递给了后端。我会检查它是否是根本原因。
标签: google-drive-api google-authentication google-picker google-slides-api google-python-api