首页 > 解决方案 > 无法通过其 ID 从 Google Drive 下载文件

问题描述

$ pip3 list | grep googl
google-api-python-client 1.7.9    
google-auth              1.6.3    
google-auth-httplib2     0.0.3    
google-auth-oauthlib     0.4.0  

我可以成功列出共享给我的文件。但是当我尝试通过其 id 下载现有文件时出现“找不到文件”错误。如何通过 id 下载文件?

列出文件的脚本

from __future__ import print_function
import pickle
import os.path
import io
import sys
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
TOKEN_FILE = 'tockenRead.pickle'

def main():
    """Shows basic usage of the Drive v3 API.
    Prints the names and ids of the first 10 files the user has access to.
    """
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists(TOKEN_FILE):
        with open(TOKEN_FILE, 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server()
        # Save the credentials for the next run
        with open(TOKEN_FILE, 'wb') as token:
            pickle.dump(creds, token)

    service = build('drive', 'v3', credentials=creds)

    # Call the Drive v3 API
    results = service.files().list(
        q="mimeType != 'application/vnd.google-apps.folder'",
        pageSize=10,
        fields="nextPageToken, files(id, name)"
    ).execute()
    items = results.get('files', [])

    if not items:
        print('No files found.')
    else:
        print('Files:')
        for item in items:
            print(u'{0} ({1})'.format(item['name'], item['id']))

if __name__ == '__main__':
    main()

结果

$ python3 list_files.py 
Files:
20140810_125633.mp4 (1SwYm5Z1zPczZnDulmsbA9wrEJ-JT-hwE)
Getting started (0B3K2QXOGSOFRc3RhcnRlcl9maWxl)

用于下载 id 为 1SwYm5Z1zPczZnDulmsbA9wrEJ-JT-hwE 文件的脚本

from __future__ import print_function
import pickle
import os.path
import io
import sys
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/drive.file']
TOKEN_FILE = 'tokenWrite.pickle';

def downloadFile(driveService, fileId):
    request = driveService.files().get_media(fileId=fileId)
    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))

def main():
    """Shows basic usage of the Drive v3 API.
    Prints the names and ids of the first 10 files the user has access to.
    """
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists(TOKEN_FILE):
        with open(TOKEN_FILE, 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server()
        # Save the credentials for the next run
        with open(TOKEN_FILE, 'wb') as token:
            pickle.dump(creds, token)

    service = build('drive', 'v3', credentials=creds)

    downloadFile(service, '1SwYm5Z1zPczZnDulmsbA9wrEJ-JT-hwE')

if __name__ == '__main__':
    main()

错误

$ python3 download_files.py 
Please visit this URL to authorize this application: https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=619229308650-91gkhdgo7v0jbt6df1phahmq868eb7gd.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&state=4mP9kgVJQD4ETOu5JjIRQFBLcyViAG&access_type=offline&code_challenge=ybCzMgZ2SOXdrpZZYn1dq9nSJk8wMtLo7Deg_Xix9So&code_challenge_method=S256
Traceback (most recent call last):
  File "download_files.py", line 52, in <module>
    main()
  File "download_files.py", line 49, in main
    downloadFile(service, '1SwYm5Z1zPczZnDulmsbA9wrEJ-JT-hwE')
  File "download_files.py", line 21, in downloadFile
    status, done = downloader.next_chunk()
  File "/usr/local/lib/python3.7/site-packages/googleapiclient/_helpers.py", line 130, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/googleapiclient/http.py", line 705, in next_chunk
    raise HttpError(resp, content, uri=self._uri)
googleapiclient.errors.HttpError: <HttpError 404 when requesting https://www.googleapis.com/drive/v3/files/1SwYm5Z1zPczZnDulmsbA9wrEJ-JT-hwE?alt=media returned "File not found: 1SwYm5Z1zPczZnDulmsbA9wrEJ-JT-hwE.">

标签: pythonpython-3.xgoogle-drive-api

解决方案


这个答案怎么样?

问题原因:

当我看到你的脚本时,我注意到下面脚本的范围与上面的脚本不同。我认为这是您的问题的原因。

在上面的脚本中,https://www.googleapis.com/auth/drive.metadata.readonly使用了。另一方面,在下面的脚本中,https://www.googleapis.com/auth/drive.file使用了。

官方文件说的范围https://www.googleapis.com/auth/drive.file如下。

查看和管理您使用此应用打开或创建的 Google Drive 文件和文件夹

这意味着当您的脚本使用 的范围上传文件时https://www.googleapis.com/auth/drive.file,您可以使用范围检索文件。但例如手动上传文件到Google Drive时https://www.googleapis.com/auth/drive.file,即使文件与你共享,也无法在范围内下载文件。

为了下载文件,以下解决方法怎么样?

解决方法 1:

您使用范围 of https://www.googleapis.com/auth/driveorhttps://www.googleapis.com/auth/drive.readonly代替https://www.googleapis.com/auth/drive.file.

解决方法 2:

如果您需要使用 的范围https://www.googleapis.com/auth/drive.file,它会使用 的范围上传文件https://www.googleapis.com/auth/drive.file。这样,文件可以通过示波器下载。

笔记:

  • 当您更改范围时,请删除文件tokenWrite.pickle并重新授权范围并创建新的tokenWrite.pickle. 这样,您可以使用新的作用域。请注意这一点。

参考:

如果我误解了您的问题并且这不是您想要的方向,我深表歉意。


推荐阅读