【问题标题】:Google drive python api: export never completes.Google drive python api:导出永远不会完成。
【发布时间】:2016-08-08 13:41:55
【问题描述】:

总结:

我有一个问题,有时用于 python 的 google-drive-sdk 没有检测到正在导出的文档的结尾。似乎认为谷歌文档是无限大的。

我遵循的背景、源代码和教程:

我正在开发我自己的基于 python 的 google-drive 备份脚本(一个带有很好的 CLI 界面用于浏览的脚本)。 git link for source code

它仍在制作中,目前仅查找新文件并下载它们(使用“拉”命令)。

为了执行最重要的 google-drive 命令,我按照官方 google drive api 教程下载媒体。 here

什么有效:

当文档或文件是非 google-docs 文档时,会正确下载该文件。但是,当我尝试“导出”文件时。我看到我需要使用不同的 mimeType。我有一本字典。

例如:我在导出文档时将application/vnd.google-apps.document 映射到application/vnd.openxmlformats-officedocument.wordprocessingml.document

从谷歌驱动器下载谷歌文档文档时,这似乎工作正常。我的意思是:我的while循环代码status, done = downloader.next_chunk()最终将done设置为true,下载完成。

什么不起作用:

但是,在某些文件上,done 标志永远不会到达true,并且脚本将永远下载。这最终达到了几个 Gb。也许我正在寻找错误的标志,表明在导出时文件已完成。我很惊讶 google-drive 从来没有抛出错误。有谁知道是什么原因造成的?

当前状态

目前,我的代码中禁用了导出 google 文档。

当我使用诸如“drive by rakyll”之类的脚本(至少是我拥有的版本)时,只需放置一个指向在线副本的链接。我真的很想进行适当的导出,以便我的离线系统可以维护驱动器上所有内容的完整备份。

附:为了其他人找到此页面,可以输入“您应该使用此服务而不是 api”。我知道还有其他服务可以解决这个问题,但我真的很想探索驱动 API 功能,以便与我自己的其他系统集成。

【问题讨论】:

  • 通过此documentation,确保请求是由经过身份验证的用户通过 OAuth 2.0 协议发出的authorized。除了应用程序可能需要的其他 scopes(例如 https://www.googleapis.com/auth/drive)之外,所有尝试导入或导出 Google Apps 脚本项目的应用程序都必须请求特殊范围 https://www.googleapis.com/auth/drive.scripts
  • 我已将其设置为完整范围:googleapis.com/auth/drive。此外,如果范围错误,我不会看到它实际上对某些出口有效。我认为这与拉多个块有关。
  • 这里也一样!你找到问题了吗?谢谢!
  • 我发现了问题。我正在使用 v3 API,从 Google 网站复制了 Python 代码。 API 调用永远不会完成,因为(我花了一段时间才发现),HTTP 调用不返回 Content-Length。我还没有找到解决方案。

标签: python google-drive-api


【解决方案1】:

好的。我在这里找到了一个伪解决方案。

问题在于 Google API 从不返回 Content-Length 并且响应是在 Chunks 中完成的。但是,返回的块是错误的,或者 Python API 无法正确处理它。

我所做的是,获取MediaIoBaseDownload from here 的代码

我保持不变,但改变了这部分:

if 'content-range' in resp:
    content_range = resp['content-range']
    length = content_range.rsplit('/', 1)[1]
    self._total_size = int(length)
elif 'content-length' in resp:
    self._total_size = int(resp['content-length'])
else:
    # PSEUDO BUG FIX: No content-length, no chunk info, cut the response here.
    self._total_size = self._progress 

最后的else 是我添加的。我还通过设置DEFAULT_CHUNK_SIZE = 2*1024*1024 更改了默认块大小。您还必须从该文件中复制一些导入,包括这个from googleapiclient.http import _retry_request, _should_retry_response

当然,这不是解决方案,它只是说“如果我不理解响应,请在此处停止”。这可能会使某些导出不起作用,但至少它不会杀死服务器。这只是在我们找到一个好的解决方案之前。

更新:

这里已经报告了错误:https://github.com/google/google-api-python-client/issues/15

截至 2017 年 1 月,唯一的解决方法是不使用 MediaIoBaseDownload 而是这样做(不适合大文件):

req = service.files().export(fileId=file_id, mimeType=mimeType)
resp = req.execute(http=http)

【讨论】:

  • 我在尝试导出文件以供下载时遇到了空的content-length 相同的问题。我在stream.getvalue() 附近使用len() 来获取文件长度,现在它可以工作了。不过,不确定性能。 stackoverflow.com/questions/26827055/…
【解决方案2】:

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

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

这是我正在使用的 sn-p:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多