谷歌驱动器python api:export永远不会完成。

时间:2016-08-08 13:41:55

标签: python google-drive-api

要点:

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

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

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

它仍在制作中,目前只找到新文件并下载它们(使用'pull'命令)。

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

什么有效:

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

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

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

什么行不通:

但是,在某些文件中,done标志永远不会到达true,脚本将永久下载。这最终达到几Gb。也许我正在寻找错误的标志,表示文件在导出时已完成。我很惊讶谷歌驱动器永远不会抛出错误。有人知道是什么原因引起的吗?

当前状态

目前我在我的代码中禁用了Google文档导出功能。

当我使用像“drive by rakyll”这样的脚本时(至少我拥有的版本)只需添加一个指向在线副本的链接。我真的想做一个正确的导出,以便我的离线系统可以维护驱动器上所有内容的完整备份。

P.S。为了其他人找到这个页面,可以使用“你应该使用这个服务而不是api”。我知道还有其他服务,但我真的希望探索与我自己的其他系统集成的drive-api功能。

2 个答案:

答案 0 :(得分:2)

行。我在这里找到了伪解决方案。

问题是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)

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