使用Python3 requests从URL下载ZIP文件:进度、路径、解压等问题咨询
Requests大体积ZIP下载相关问题解答
(1)如何输出下载进度信息
你原来的代码会一次性把所有内容加载到内存,既看不到进度,大文件还容易爆内存。修改为流式下载即可实时输出进度,示例代码如下:
import requests # 可选,用tqdm可以直接生成进度条,不需要自己算格式,使用前需执行pip install tqdm安装依赖 from tqdm import tqdm url = 'https://nlp.stanford.edu/data/glove.6B.zip' # 加stream=True开启流式下载,不会一次性加载全部内容 resp = requests.get(url, stream=True) # 获取文件总大小 total_size = int(resp.headers.get('content-length', 0)) block_size = 1024 # 每次下载1KB # 不用tqdm的版本,自己输出进度 # downloaded = 0 # for data in resp.iter_content(block_size): # downloaded += len(data) # progress = downloaded / total_size * 100 # print(f"下载进度:{progress:.2f}% | 已下载:{downloaded/1024/1024:.2f}MB / {total_size/1024/1024:.2f}MB", end='\r') # 用tqdm的版本,更美观 with tqdm(total=total_size, unit='iB', unit_scale=True) as pbar: for data in resp.iter_content(block_size): pbar.update(len(data))
如果要更详细的日志,可以额外打印请求头、响应状态码、分块下载的时间戳等信息。
(2)存储位置与相对路径使用
你当前的代码没有将下载的文件写入磁盘,所有内容仅暂存在内存中,程序退出就会丢失。你需要手动将流式下载的内容写入磁盘文件,可以直接使用相对路径,示例如下:
# 相对路径写法,代表当前脚本运行目录下的glove.6B.zip文件 save_path = './glove.6B.zip' with open(save_path, 'wb') as f: for data in resp.iter_content(block_size): f.write(data)
后续脚本只要和当前脚本在同一工作目录下运行,就可以直接用./glove.6B.zip这个相对路径读取文件。如果要确认绝对路径,可以用os.path.abspath(save_path)获取文件的完整存储路径。
(3)ZIP文件优雅解压
直接用Python内置的zipfile模块即可完成解压,不需要安装第三方依赖,示例如下:
import zipfile zip_path = './glove.6B.zip' # 解压到当前目录下的glove文件夹,会自动创建不存在的目录 extract_path = './glove/' with zipfile.ZipFile(zip_path, 'r') as zip_ref: # 解压全部文件 zip_ref.extractall(extract_path) # 如果只需要解压特定文件,可以用extract方法 # zip_ref.extract('glove.6B.100d.txt', extract_path)
如果要校验解压后的文件完整性,可以对比解压后文件的MD5值和官方提供的校验值。
(4)自定义文件名与获取默认文件名
- 自定义文件名:你在写磁盘的时候直接指定保存的文件名即可,比如上面示例里的
save_path你可以改成任意你想要的名称,比如./my_custom_name.zip。 - 获取默认文件名:优先从响应头的
Content-Disposition字段提取,如果没有该字段就取URL最后一段作为默认文件名,示例代码如下:
import re from urllib.parse import urlparse # 从Content-Disposition取文件名 content_disposition = resp.headers.get('Content-Disposition', '') if content_disposition: file_name = re.findall('filename="?([^"]+)"?', content_disposition)[0] else: # 从URL取最后一段 file_name = urlparse(url).path.split('/')[-1] print(f"默认文件名为:{file_name}")
内容的提问来源于stack exchange,提问作者kiriloff
相关产品推荐
相关产品推荐

