从 public Google 驱动器 python 下载文件:范围问题?

Downloading files from public Google Drive in python: scoping issues?

使用我对 关于如何从 public Google 驱动器下载文件的回答 我过去设法使用它们的 ID 从 python 下载图像来自 public 驱动器的脚本和 Google API v3 使用以下代码块:

from google_auth_oauthlib.flow import Flow, InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
from google.auth.transport.requests import Request
import io
import re
SCOPES = ['https://www.googleapis.com/auth/drive']
CLIENT_SECRET_FILE = "myjson.json"
authorized_port = 6006 # authorize URI redirect on the console
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE, SCOPES)
cred = flow.run_local_server(port=authorized_port)
drive_service = build("drive", "v3", credentials=cred)
regex = "(?<=https://drive.google.com/file/d/)[a-zA-Z0-9]+"
for i, l in enumerate(links_to_download):
    url = l
    file_id = re.search(regex, url)[0]
    request = drive_service.files().get_media(fileId=file_id)
    fh = io.FileIO(f"file_{i}", mode='wb')
    downloader = MediaIoBaseDownload(fh, request)
    done = False
    while done is False:
        status, done = downloader.next_chunk()
        print("Download %d%%." % int(status.progress() * 100))

与此同时,我发现 pydrive and pydrive2,Google API v2 的两个包装器允许做非常有用的事情,例如从文件夹中列出文件,并且基本上允许做同样的事情有一个更轻的语法:

from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
import io
import re
CLIENT_SECRET_FILE = "client_secrets.json"

gauth = GoogleAuth()
gauth.LocalWebserverAuth()
drive = GoogleDrive(gauth)
regex = "(?<=https://drive.google.com/file/d/)[a-zA-Z0-9]+"
for i, l in enumerate(links_to_download):
    url = l
    file_id = re.search(regex, url)[0]
    file_handle = drive.CreateFile({'id': file_id})
    file_handle.GetContentFile(f"file_{i}")

但是现在无论我使用 pydrive 还是原始 API 我似乎都无法下载相同的文件 而我却遇到了:

googleapiclient.errors.HttpError: <HttpError 404 when requesting https://www.googleapis.com/drive/v3/files/fileID?alt=media returned "File not found: fileID.". Details: "[{'domain': 'global', 'reason': 'notFound', 'message': 'File not found: fileID.', 'locationType': 'parameter', 'location': 'fileId'}]">

我尝试了所有方法并使用 Google 控制台注册了 3 个不同的应用程序,这似乎是(或不是)范围界定问题(例如参见 [​​=22=],应用程序只能访问文件在我的 Google 驱动器中或由此应用程序创建)。但是我之前(去年)没有这个问题。

当进入 Google console 时,明确将 https://www.googleapis.com/auth/drive 作为 API 的范围要求使用 use/confidentiality 的应用程序 website/conditions 填充大量字段rules/authorized 域和解释该应用程序的 YouTube 视频。但是,我将是该脚本的唯一用户。 所以我只能明确给出以下范围:

/auth/drive.appdata
/auth/drive.file
/auth/drive.install

是因为范围界定吗?有没有不需要创建主页和 youtube 视频的解决方案?

编辑 1: 这是 links_to_download:

的示例
links_to_download = ["https://drive.google.com/file/d/fileID/view?usp=drivesdk&resourcekey=0-resourceKeyValue"]

编辑 2: 它非常不稳定,有时它会毫不费力地工作,有时却不会。当我多次重新启动脚本时,我得到不同的结果。重试策略在一定程度上起作用,但有时会在数小时内多次失败。

感谢 Google 几个月前发布的 security update。这使得 link 共享更加严格,您还需要资源密钥才能将文件 in-addition 访问到 fileId

根据 documentation ,如果您想在 header X-Goog-Drive-Resource-Keys 中访问它,您还需要为更新的 link 提供资源密钥作为 fileId1/resourceKey1.

如果您在代码中应用此更改,它将正常工作。下面的示例编辑:

regex = "(?<=https://drive.google.com/file/d/)[a-zA-Z0-9]+"
regex_rkey = "(?<=resourcekey=)[a-zA-Z0-9-]+"
for i, l in enumerate(links_to_download):
    url = l
    file_id = re.search(regex, url)[0]
    resource_key = re.search(regex_rkey, url)[0]
    request = drive_service.files().get_media(fileId=file_id)
    request.headers["X-Goog-Drive-Resource-Keys"] = f"{file_id}/{resource_key}"
    fh = io.FileIO(f"file_{i}", mode='wb')
    downloader = MediaIoBaseDownload(fh, request)
    done = False
    while done is False:
        status, done = downloader.next_chunk()
        print("Download %d%%." % int(status.progress() * 100))

好吧,资源键的正则表达式是我很快制作的,所以不能确定它是否支持所有情况。但这为您提供了解决方案。 现在,您可能需要根据此收听新旧 links 并设置更改。