带进度条的文件下载器
基础知识
获取文件大小 不难知道,要做一个进度条展示下载进度,我们得事先知道文件的大小以及每次写入文件的大小。还是以这个文件链接为例,展示如何获取待下载的文件大小
# 导入requests 库 import requests # 文件下载直链 url = 'https://issuecdn.baidupcs.com/issue/netdisk/yunguanjia/BaiduNetdisk_7.2.8.9.exe' # 请求头 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE' } # 发起 head 请求,即只会获取响应头部信息 response = requests.head(url, headers=headers) # 文件大小,以 B 为单位 file_size = response.headers.get('Content-Length') if file_size is not None: file_size = int(file_size) print('文件大小:', file_size, 'B')
代码运行输出
文件大小: 67765560 B
分块获取响应内容
上面的文件大小为:67765560 B。如果我们一次性下载 67765560 B 这么大的文件的话,进度条的跨度显然太大了,那么做这么一个进度条的意义并不大,所以我们需要考虑通过一个循环,分多次连续地读取响应直到读取完毕。
# 导入requests 库 import requests # 文件下载直链 url = 'https://issuecdn.baidupcs.com/issue/netdisk/yunguanjia/BaiduNetdisk_7.2.8.9.exe' # 请求头 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE' } # 发起 head 请求,即只会获取响应头部信息 head = requests.head(url, headers=headers) # 文件大小,以 B 为单位 file_size = head.headers.get('Content-Length') if file_size is not None: file_size = int(file_size) response = requests.get(url, headers=headers, stream=True) # 一块文件的大小 chunk_size = 1024 # 记录已经读取的文件大小 read = 0 for chunk in response.iter_content(chunk_size=chunk_size): read += chunk_size read = min(read, file_size) print(f'已读取: {read} 总大小: {file_size}')
部分输出结果
已读取: 1024 总大小: 67765560 已读取: 2048 总大小: 67765560 已读取: 3072 总大小: 67765560 已读取: 4096 总大小: 67765560 已读取: 5120 总大小: 67765560 已读取: 6144 总大小: 67765560 已读取: 7168 总大小: 67765560 已读取: 8192 总大小: 67765560
通过以上操作,我们成功实现分段、连续下载文件。但是输出显然太多了,我们更希望有一个单行的进度条。 这里不得不说到 tqdm 这个进度条库
一个 tqdm 的使用例子
import time from tqdm import tqdm total = 100 for _ in tqdm(range(total)): time.sleep(0.1)
在终端或者jupyter运行上面的代码即可看到下面的动图如果想一次更新指定次数个进度怎么办呢?比如说进度总共是 100 ,每 10 个刷新一次进度
实现代码例子如下
mport time from tqdm import tqdm # 总进度 total = 100 # 每次刷新的进度 step = 10 # 总共要刷新的次数 flush_count = total//step bar = tqdm(total=total) for _ in range(flush_count): time.sleep(0.1) bar.update(step) bar.close()i
以上代码可实现 每 10 个单位刷新一次直进度满 100
下面来给我们的下载器加进度条吧!
# 导入requests 库 import requests # 导入 tqdm from tqdm import tqdm # 文件下载直链 url = 'https://issuecdn.baidupcs.com/issue/netdisk/yunguanjia/BaiduNetdisk_7.2.8.9.exe' # 请求头 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE' } file_name = 'BaiduNetdisk_7.2.8.9.exe' # 发起 head 请求,即只会获取响应头部信息 head = requests.head(url, headers=headers) # 文件大小,以 B 为单位 file_size = head.headers.get('Content-Length') if file_size is not None: file_size = int(file_size) response = requests.get(url, headers=headers, stream=True) # 一块文件的大小 chunk_size = 1024 bar = tqdm(total=file_size, desc=f'下载文件 {file_name}') with open(file_name, mode='wb') as f: # 写入分块文件 for chunk in response.iter_content(chunk_size=chunk_size): f.write(chunk) bar.update(chunk_size) # 关闭进度条 bar.close()
代码运行过程如下
就这样,我们成功实现了一个带进度条的文件下载器! 为了调用方便,我们可以考虑把它封装为函数,这里我直接附上代码了