本教程详细介绍了如何在Google Colab环境中,无需挂载Google Drive,从公共Google Drive链接下载并解压ZIP文件。文章分析了常见的`BadZipFile`错误原因,提供了使用`requests`库构建正确下载URL的方法,并重点推荐了更便捷、鲁棒的`gdown`库,以确保文件能够被正确识别和处理,从而实现可复现的数据集下载流程。
在数据科学和机器学习项目中,经常需要从外部源下载数据集。Google Drive因其便捷的共享功能,常被用作数据集的托管平台。然而,在Google Colaboratory (Colab) Notebook中直接从公共Google Drive链接下载并解压ZIP文件时,开发者可能会遇到一些挑战,特别是当不希望挂载个人Google Drive以保持环境的可复现性时。本文将深入探讨如何高效、正确地在Colab中完成这一任务。
直接从Google Drive的共享链接(例如https://drive.google.com/drive/folders/... 或 https://drive.google.com/file/d/...)尝试下载文件,往往不会直接得到文件本身,而是会收到一个HTML页面。这是因为Google Drive在提供文件下载前,通常会经过一个中间页面,用于显示文件信息、病毒扫描警告(针对大文件)或权限验证。
当使用requests库或wget命令尝试下载这类链接时,如果接收到的内容是HTML而不是实际的ZIP文件二进制数据,那么尝试使用zipfile模块解压时就会抛出BadZipFile: File is not a zip file的错误。
诊断方法:检查Content-Type头部
在尝试解压前,检查HTTP响应的Content-Type头部是诊断此类问题的关键。如果Content-Type显示为text/html而不是application/zip,则说明下载到的并非ZIP文件。
import requests
file_id = '1fdFu5NGXe4rTLYKD5wOqk9dl-eJOefXo' # 替换为你的Google Drive文件ID
download_url = f'https://drive.google.com/uc?export=download&id={file_id}'
response = requests.get(download_url)
print(f"Content-Type: {response.headers.get('Content-Type')}")如果输出显示Content-Type: text/html,则需要调整下载策略。
要从Google Drive直接下载文件,需要构造一个特定的下载URL,通常格式为 https://drive.google.com/uc?export=download&id=FILE_ID。其中,FILE_ID是Google Drive文件中唯一的标识符,可以从文件的共享链接中提取(例如,https://drive.google.com/file/d/FILE_ID/view)。
步骤:
以下是一个完整的示例代码:
import requestsimport io import zipfile import os # 替换为你的Google Drive文件ID file_id = '1fdFu5NGXe4rTLYKD5wOqk9dl-eJOefXo' # 示例ID,请替换为实际ZIP文件的ID download_url = f'https://drive.google.com/uc?export=download&id={file_id}' # 目标保存路径 output_path = '/content/downloaded_zip.zip' extraction_dir = '/content/extracted_data/' print(f"尝试从 {download_url} 下载文件...") # 处理Google Drive大文件下载时的病毒扫描警告 # Google Drive对于大文件可能会返回一个警告页面,需要模拟点击“下载” def download_file_from_google_drive(id, destination): URL = "https://drive.google.com/uc?export=download" session = requests.Session() response = session.get(URL, params = { 'id' : id }, stream = True) token = get_confirm_token(response) if token: params = { 'id' : id, 'confirm' : token } response = session.get(URL, params = params, stream = True) save_response_content(response, destination) def get_confirm_token(response): for key, value in response.cookies.items(): if key.startswith('download_warning'): return value return None def save_response_content(response, destination): CHUNK_SIZE = 32768 with open(destination, "wb") as f: for chunk in response.iter_content(CHUNK_SIZE): if chunk: # filter out keep-alive new chunks f.write(chunk) # 执行下载 try: download_file_from_google_drive(file_id, output_path) print(f"文件已下载到: {output_path}") # 检查下载的文件是否是有效的ZIP文件 if not os.path.exists(output_path) or os.path.getsize(output_path) == 0: print("错误:下载的文件为空或不存在。请检查文件ID和权限。") else: # 解压ZIP文件 os.makedirs(extraction_dir, exist_ok=True) with zipfile.ZipFile(output_path, 'r') as zip_ref: zip_ref.extractall(extraction_dir) print(f"ZIP文件已成功解压到: {extraction_dir}") except Exception as e: print(f"下载或解压过程中发生错误: {e}") print("请确认文件ID是否正确,以及文件是否设置为公开访问。")
注意事项:
gdown是一个专门用于从Google Drive下载文件的Python库,它封装了处理Google Drive下载链接、病毒扫描警告等复杂逻辑,使得下载过程更加简洁和鲁棒。对于在Colab中进行数据下载,gdown是高度推荐的工具。
步骤:
# 1. 安装 gdown 库
!pip install gdown -q
import gdown
import zipfile
import os
# 替换为你的Google Drive文件ID
file_id = '1fdFu5NGXe4rTLYKD5wOqk9dl-eJOefXo' # 示例ID,请替换为实际ZIP文件的ID
output_path = '/content/downloaded_zip.zip'
extraction_dir = '/content/extracted_data/'
print(f"使用 gdown 从 Google Drive 下载文件 ID: {file_id}")
try:
# 2. 使用 gdown 下载文件
# quiet=False 会显示下载进度
gdown.download(id=file_id, output=output_path, quiet=False)
print(f"文件已下载到: {output_path}")
# 检查下载的文件是否是有效的ZIP文件
if not os.path.exists(output_path) or os.path.getsize(output_path) == 0:
print("错误:下载的文件为空或不存在。请检查文件ID和权限。")
else:
# 3. 解压ZIP文件
os.makedirs(extraction_dir, exist_ok=True)
with zipfile.ZipFile(output_path, 'r') as zip_ref:
zip_ref.extractall(extraction_dir)
print(f"ZIP文件已成功解压到: {extraction_dir}")
except Exception as e:
print(f"下载或解压过程中发生错误: {e}")
print("请确认文件ID是否正确,以及文件是否设置为公开访问。")
# 验证解压内容 (可选)
# print("\n解压后的文件列表:")
# for root, dirs, files in os.walk(extraction_dir):
# for name in files:
# print(os.path.join(root, name))gdown库的优点在于它能够自动处理Google Drive的各种下载重定向和警告,使得代码更加简洁和健壮。
!wget --no-check-certificate -O '/content/file.zip' 'https://drive.google.com/uc?export=download&id=YOUR_FILE_ID'
但wget在处理Google Drive的大文件病毒扫描警告时可能不如gdown灵活。
在Google Colab中从公共Google Drive下载并解压ZIP文件,关键在于理解Google Drive的下载机制,并构造正确的下载URL。对于大多数场景,推荐使用gdown库,它提供了一种简洁而强大的解决方案,能够自动处理Google Drive下载的复杂性。如果需要更精细的控制,requests库配合正确的逻辑也可以实现。无论选择哪种方法,始终要确保文件ID的正确性以及文件的公共可访问性,以保证数据下载流程的顺畅和可复现。