首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从python中的公共Google下载文件:范围问题?

从python中的公共Google下载文件:范围问题?
EN

Stack Overflow用户
提问于 2022-03-03 19:51:06
回答 1查看 2.1K关注 0票数 6

使用我对我的问题关于如何从公共谷歌驱动器下载文件的答案,我过去曾尝试使用python脚本中的I和使用以下代码块从公共驱动器下载其I的Google v3:

代码语言:javascript
运行
复制
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))

同时,我发现了吡喹酮pydrive2,这两个包装器围绕着Google v2,允许做非常有用的事情,比如列出文件夹中的文件,并且基本上允许使用更轻巧的语法来完成相同的事情:

代码语言:javascript
运行
复制
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 ,我似乎都无法下载相同的文件,而是遇到了以下情况:

代码语言:javascript
运行
复制
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'}]">

我什么都试过了,用谷歌控制台注册了3个不同的应用程序,这看起来可能是(或者不是)一个范围界定的问题(比如这个答案,应用程序只能访问我的谷歌驱动器中的文件或这个应用程序创建的文件)。然而,我以前(去年)没有这个问题。

当进入Google控制台时,明确地将https://www.googleapis.com/auth/drive作为API的一个范围,将大量字段填充到应用程序的网站/使用条件/保密规则/授权域以及解释应用程序的youtube视频中。不过,我将是这个脚本的唯一用户。因此,我只能显式地给出以下范围:

代码语言:javascript
运行
复制
/auth/drive.appdata
/auth/drive.file
/auth/drive.install

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

编辑1:这里的links_to_download的一个示例

代码语言:javascript
运行
复制
links_to_download = ["https://drive.google.com/file/d/fileID/view?usp=drivesdk&resourcekey=0-resourceKeyValue"]

编辑2: -它是超级不稳定的,有时它没有汗水,有时它没有。当我多次重新启动脚本时,我得到了不同的结果。重试策略在一定程度上起作用,但有时几个小时多次失败。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-04 12:57:34

感谢谷歌几个月前发布的安全更新。这使得链接共享更加严格,您还需要资源密钥来访问fileId之外的文件。

按照文档,如果您想以fileId1/resourceKey1的形式在标头X-Goog-Drive-Resource-Keys中访问它,也需要为更新的链接提供资源键。

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

代码语言:javascript
运行
复制
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))

嗯,资源键的正则表达式是我很快做的,所以不能确定它是否支持每一种情况。但这为你提供了解决办法。现在,您可能必须在此基础上听取新旧链接,并设置更改。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71343002

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档