干运维这几年,没少被 Google Drive 的下载链接坑过。很多开源数据集、模型权重、备份压缩包都放在 Google Drive 上,网页打开很顺畅,真到了服务器上想直接拉取,各种报错就来了:wget 下来是个 HTML、curl 下来提示需要登录、文件超过 2GB 直接拒绝下载。这篇文章就把我在 Linux 服务器上直接下载 Google Drive 数据的几种方案一次性捋清楚,从一条命令搞定的 gdown,到适合大规模同步的 rclone,再到自己写 curl 脚本理解底层协议。适合天天跟服务器打交道的人,也适合刚接触 Linux 的算法工程师照着抄。
1. 为什么在服务器上下载 Google Drive 数据是个麻烦事
1.1 你复制的是网页地址,不是下载地址
在浏览器里打开 Google Drive 分享链接,地址栏显示的是https://drive.google.com/file/d/文件ID/view。这个链接是给人看的网页,不是给机器用的下载接口。你把这条链接直接丢给wget或curl,服务器拿到的是一段 HTML 页面,里面确实藏着文件信息,但下载行为不会自动触发。如果文件比较小,Google 会给你一个重定向,指向drive.google.com/uc?export=download&id=文件ID,wget 加上-L参数还能勉强跟过去。但文件一旦超过某个阈值,Google 会先弹出一个“无法安全下载”的病毒扫描确认页,要求你提交一个 confirm token,wget 到这一步就彻底断掉了。
很多人在这一步就卡住了,以为是网络问题,其实不是。Google Drive 的下载协议本身就有两套逻辑:小文件走直接重定向,大文件走确认页。你需要在脚本里模拟一次表单提交,把 Google 下发的 confirm 参数带上下载请求,才能拿到真实文件流。仅靠“复制链接 + wget”是行不通的。
1.2 大文件还有一道“病毒扫描”关卡
Google Drive 为了安全,会对超过 100MB 的文件做一次病毒扫描。你点击下载时,会看到“Google Drive 无法扫描此文件以查找病毒”的提示,然后给你两个按钮:“仍然下载”和“取消”。这个交互在浏览器里很简单,但在服务器上就变成了一道协议门槛:你需要先 GET 一次下载页,从返回的 HTML 里提取一个 name 为confirm的隐藏字段值,然后把这个值拼到下载 URL 的confirm参数里,再发起第二次请求。这样 Google 才认为你“确认了仍然下载”,开始正经输出文件流。
不同的服务器环境、不同版本的 curl 或者 wget 处理这个流程时会有各种细节差异,比如 cookie 没有保持、重定向次数不够、URL 参数顺序不对。所以更推荐直接用现成工具,而不是重复造轮子。当然,如果你需要在没有 Python 环境、不能装第三方包的裸机器上操作,那就必须理解这套协议,自己用 shell 实现。
2. 最省事的方案:用 gdown 一条命令搞定
2.1 安装与环境准备
gdown是我目前用过最省心的 Google Drive 下载工具。它是基于 Python 的,内部模拟了浏览器下载的完整流程,自动处理大文件确认 token、文件夹打包下载、文件名解析,甚至还能接 Google Drive API 来解决限流问题。安装很简单:
pip install gdown如果你的服务器上有多个 Python 环境,注意别装错环境。建议用python3 -m pip install gdown确认装到了当前 Python 对应的 pip 上。装完之后命令行里就有gdown了。没有 sudo 权限的话,可以加--user,或者用虚拟环境。
gdown 的原理不算高深:它先请求 Google Drive 的下载接口,如果是大文件,就解析 HTML 里的 confirm 表单并自动提交。相比 wget,它最大的优势是“不用管过程,只要给链接或文件 ID”。适合临时把文件拉到服务器上,用完即走。
2.2 下载单个文件
下载一个公开分享、任何人都能查看的文件,一行就够:
gdown https://drive.google.com/uc?id=文件ID # 或者更简单,直接给文件ID gdown 文件ID # 用 view 链接也可以 gdown https://drive.google.com/file/d/文件ID/viewgdown 会显示下载进度、文件大小和保存的文件名。默认保存到当前目录,可以用-O指定输出路径:
gdown https://drive.google.com/uc?id=文件ID -O /data/models/weights.h5这里有个细节:Google Drive 的分享文件分两种权限,“任何知道链接的人”和“特定用户”。gdown 只能下载前者,也就是无需登录就能看的文件。如果链接要求登录,gdown 会报错Access denied。这种情况要么让文件所有者把共享权限改成“任何人可查看”,要么就得走 API 密钥或者 Service Account,后面会提到。
2.3 下载整个文件夹
gdown 也支持文件夹。Google Drive 的文件夹链接长这样:https://drive.google.com/drive/folders/文件夹ID。下载整个文件夹:
gdown https://drive.google.com/drive/folders/文件夹ID -O /data/dataset --foldergdown 会遍历文件夹里的所有文件,然后打包成一个 tar 或者 zip 格式的压缩包再下载。文件特别多、特别大的时候,这个过程会很慢,而且 gdown 是边打包边下载,如果中间断掉,只能重新再来。我更推荐用--remaining-ok参数,这个参数允许在 Google 显示“下载配额已用完”时仍然尝试逐文件下载。实测下来,对于那种几十 GB 的大目录,gdown 并不稳定,更适合下载单文件或者小规模文件夹。
3. 数据工程标配:用 rclone 做同步和挂载
3.1 初始化配置 Google Drive 远程
如果你需要频繁从 Google Drive 同步数据到服务器,或者要定期备份,rclone 比 gdown 靠谱得多。rclone 是一个命令行同步工具,支持几十种存储后端,Google Drive 是它支持得最完善的一类。它不只是下载,还能增量同步、断点续传、限速、双向对比,甚至可以把 Google Drive 挂载成本地目录。
安装 rclone:
curl https://rclone.org/install.sh | sudo bash配置 Google Drive 远程存储:
rclone config交互式配置过程会让你选远程类型,输入drive。它会问你 client_id 和 client_secret,直接回车使用默认值也能跑,但缺点很明显:默认 client_id 是 rclone 官方的,所有用默认配置的人共享这个 API key,Google 的速率限制会更严格。如果你经常被Rate limit exceeded报错烦到,建议去 Google Cloud Console 自己创建一个 OAuth 客户端,把 client_id 填进去,限制会宽松不少。
配置过程中,rclone 会在终端打印一条 URL,要求你在浏览器里打开并授权。服务器没有浏览器怎么办?两个办法:一是用rclone authorize "drive"在本地电脑上执行一次,把得到的 token 粘贴到服务器配置里;二是用 rclone 的--drive-service-account-credentials选项配置 Service Account,适合纯无人值守的服务器环境。
3.2 复制、校验、断点续传
配置完成后,你会在 rclone 里看到一个远程名字,比如gdrive:。接下来的操作跟本地文件复制差不多:
# 把 Google Drive 上某个文件夹同步到本地 rclone copy gdrive:data /data/google_drive --progress --transfers 4 # 把本地文件备份到 Google Drive rclone copy /data/backup gdrive:backup --progressrclone copy只复制新增或变化的文件,已经存在的同名文件会跳过,天然支持断点续传。如果下载中断,再次执行同一条命令会从断点继续,不会从头再来。这个特性在下载大文件时非常实用。如果你想要完全镜像,也就是本地和远程保持一模一样,用rclone sync,但注意 sync 会删除本地多余的文件,用之前想清楚。
还可以给下载限速,避免占满服务器带宽:
rclone copy gdrive:data /data/google_drive --bwlimit 10M--bwlimit 10M表示限速 10MB/s。同时可以用--transfers调整并发数,默认 4 在百兆带宽下够用,但千兆服务器可以适当调高到 8 或 16,前提是 Google 没有限流。
3.3 把 Google Drive 挂载为本地目录
rclone 还支持用 FUSE 把 Google Drive 挂载成服务器上的一个目录,相当于给服务器加了一块“云硬盘”。挂载之后,你可以用普通文件操作的方式读取 Google Drive 里的数据,甚至直接跑训练脚本。挂载命令:
rclone mount gdrive: /mnt/gdrive --allow-other --daemon挂载以后,/mnt/gdrive就是一个看起来像本地目录的存在。但我要提醒一句:别把随机读取型任务直接跑在挂载盘上。Google Drive API 的延迟和随机读取性能远不如本地 SSD,尤其图片、小文件这类场景,API 请求量会迅速把你打到配额上限。数据还是要先拉到本地磁盘再处理。挂载更适合偶尔浏览目录结构、或者要手动挑几个文件下载的情况。
4. 自己写 curl/wget 脚本:彻底搞懂下载协议
4.1 下载链接的构成拆解
有时候你手里的服务器特别干净,不想装 Python、不想装 rclone,只有 curl 和 wget。这种场景下你必须自己处理 Google Drive 的下载协议。先拆解链接,Google Drive 的分享链接主要有两种:
- 文件链接:
https://drive.google.com/file/d/文件ID/view - 目录链接:
https://drive.google.com/drive/folders/文件夹ID
直接下载单个小文件,其实有一个稳定的 URL 格式:
curl -L "https://drive.google.com/uc?export=download&id=文件ID" -o 文件名export=download是告诉 Google 这个请求是下载文件而不是打开网页。-L让 curl 跟随重定向。对小文件,这个命令能正常拿到内容。但大文件会在重定向后的页面里插入确认表单,所以需要多一步提取 confirm 参数。
4.2 处理大文件确认页
大文件下载的第一步,先用 curl 请求一次带export=download的地址,把 HTML 抓下来:
curl -c cookie.txt -s "https://drive.google.com/uc?export=download&id=文件ID" > page.html然后从page.html里提取 confirm 值。典型 HTML 片段长这样:
<form id="download-form" action="https://drive.google.com/uc?export=download&id=xxx" method="post"> <input type="hidden" name="confirm" value="TmpVbQ"> ... </form>提取的方法不唯一,可以用 grep 或 sed:
confirm=$(grep -o 'name="confirm" value="[^"]*"' page.html | cut -d '"' -f 4)注意 grep 的正则在不同环境有差异,最好用固定的匹配模式。拿到 confirm 之后,第二次请求加上这个参数:
curl -C - -b cookie.txt -L "https://drive.google.com/uc?export=download&id=文件ID&confirm=$confirm" -o 输出文件名-b cookie.txt是为了带上第一次请求里 Google 设置的 cookie,有些情况下这一步不能省。-C -支持断点续传,下载到一半断了再跑一次会从断点继续。
4.3 写成可复用的 shell 函数
每次写这么一串命令太累,我习惯把它封装成一个 shell 函数放到/usr/local/bin/gdget里:
#!/bin/bash # gdget file_id output_name gdget() { id=$1 out=$2 if [ -z "$out" ]; then out="$id"; fi confirm=$(curl -c /tmp/gd_cookie -s "https://drive.google.com/uc?export=download&id=$id" | grep -o 'name="confirm" value="[^"]*"' | cut -d '"' -f 4) if [ -z "$confirm" ]; then # 小文件,无需确认 curl -C - -L "https://drive.google.com/uc?export=download&id=$id" -o "$out" else curl -C - -b /tmp/gd_cookie -L "https://drive.google.com/uc?export=download&id=$id&confirm=$confirm" -o "$out" fi }用的时候:
source /usr/local/bin/gdget gdget 文件ID 文件名.zip这个脚本不依赖 Python,任何带 curl 的 Linux 机器都能跑。但缺点也很明显:文件夹下载支持不了,文件名需要自己指定,如果共享文件设置了权限或者 IP 被限流,一样会失败。对我来说,写这个脚本最大的价值是理解了 Google Drive 下载协议的本质。如果你以后遇到 gdown 崩溃但又想知道它到底在干嘛,这个脚本就是最好的调试工具。
5. 常见问题与排查技巧
5.1 下载到 HTML、403、quota exceeded 的处理
这一类问题是出现频率最高的,我整理了排查思路:
| 现象 | 根本原因 | 解决办法 |
|---|---|---|
| 下载到 HTML 文件 | 直接请求了 view 链接,或没加-L | 用uc?export=download&id=格式,加-L |
| 下载页出现“无法安全下载” | 大文件确认 token 没处理 | 用 gdown,或按第 4 节方法提取 confirm |
| 403 禁止访问 | 文件未公开分享,或 IP 被限流 | 确认文件权限改为“任何人”,或换 IP |
报错Too many users have viewed or downloaded this file recently | Google Drive 配额超限 | 等 24 小时,或用自己的 client_id 走 API |
| 文件夹打包下载一半断掉 | gdown 对超大文件夹支持不佳 | 改用 rclone,或逐文件下载 |
关于配额超限,多说一句。Google Drive 有一个基于 IP 的下载限制,同一个 IP 在短时间内下载过多文件时,就会触发这个提示。服务器如果是共享 IP 或者 NAT 出口,很容易踩中。gdown 的--remaining-ok参数可以在这种时候继续尝试,但速度会变慢。更好的办法是配置 Google Drive API 自己的 OAuth client,并且用 Service Account 的凭据去下载,绕开基于普通网页端的匿名配额。rclone 在配置client_id之后,配额也会宽松一些。
5.2 下载目录失败、文件名乱码、限速问题
有朋友跟我说,用 gdown 下载文件夹,大目录总是失败。我的经验是:不要用 gdown 下载大目录,改用 rclone。rclone 会遍历文件夹里的每个文件,逐个下载,支持断点续传。哪怕中途断掉,重跑一次会跳过已下载文件,不会从头再来。这是 gdown 没法比的。
文件名乱码通常出现在自己写 curl 脚本的时候。Google Drive 返回的文件名在响应头的Content-Disposition字段里,中文名会做 URL 编码。要正确还原文件名,得对响应头做一次解码。gdown 和 rclone 都处理好了这个,如果你用裸 curl,建议用-OJ参数让 curl 自动使用服务器返回的文件名,但偶尔也会遇到不标准的响应头。实在不行就自己指定-o文件名,不纠结。
限速问题分两种。一种是 Google 主动限流,表现是下载速度波动很大、时不时降到几十 KB/s。这种情况可以降低并发,或者等待高峰期过去。另一种是服务器网络带宽本身限制,需要检查服务器的带宽监控。我的习惯是 rclone 加--bwlimit明确控制速度,避免把服务器的带宽吃满,影响线上业务。
5.3 反直觉的坑与建议
最后分享几个踩过坑后才明白的点。
第一,注意磁盘空间和 inode。Google Drive 上单个文件显示是 5GB,但下载到本地时文件系统上占用的空间可能因为预分配而显得更大。df -h明明还有空间,df -i却爆了 inode,这种情况在小文件多的目录同步时经常发生。下载前先检查df -h和df -i。
第二,rclone copy 不会校验文件内容?其实默认会做校验,但对于大文件,它默认用修改时间和大小判断是否需要传输。如果源文件在 Google Drive 上被修改了,但大小和时间戳没变,rclone 可能跳过。稳妥起见,关键数据下载完可以加上--checksum强制校验,虽然会慢一些,但更可靠。
第三,不要把账号服务账号绑定到 Google Drive 的某个权限范围后,就忘了它只能访问该账号下被授权的文件。用 Service Account 下载别的地方分享给你的文件时,需要把文件夹共享给 Service Account 的服务邮箱,否则会 404。这个坑能卡你半小时。
6. 最后再分享一个小技巧
我的实际体会是,这几种方式不是互斥的,而是分场景配合使用。
- 临时拉一个几 GB 的模型文件,用 gdown,简单直接;
- 每天要从 Google Drive 同步一批数据到服务器做增量更新,用 rclone,配上自己的 client_id,稳定且支持断点续传;
- 裸机没有任何 Python 和额外工具,也可以用我上面那个 shell 函数应急;
- 如果遇到配额限制导致下载失败,优先考虑换一个不同出口 IP,其次才考虑等配额刷新。对于生产环境,建议把数据先同步到一台中转机,再分发到其他服务器,避免多台机器同时去拉同一个 Google Drive 链接,触发更严格的限流。
另外,下载完大文件之后,顺手做一次md5sum或sha256sum。Google Drive 上的文件有时候会上传不完整,尤其是别人分享的数据集,校验一下落盘内容永远不吃亏。我就在一次下载好几十个压缩包之后吃过亏,解压到一半才发现某个包是坏的,只能重新拉,耽误了不少时间。
这些就是我在服务器上直接下载 Google Drive 数据的全部经验了。下次你再遇到服务器上拉不动 Drive 文件的情况,先判断文件大小和形态,再对症下药,基本都能省下不少折腾时间。