Python展示文件下载进度条

本文介绍了如何在Python中使用requests库下载文件时显示进度条,通过结合tqdm库,使得大文件下载时能有直观的进度反馈,类似迅雷或百度网盘的体验。

Python展示文件下载进度条

大家好!我是晨晨💓
希望大家多多支持我!
为了感谢每一个关注我的小可爱:💓文章留言“学习”即可获取晨晨精心准备的学习大礼包书籍教程,都是无偿分享滴💓
最后——如果文章有帮助到你,记得“关注”、“点赞”、“评论”三连哦~
————————————————

前言

大家在用Python写一些小程序的时候,经常都会用到文件下载,对于一些较小的文件,大家可能不太在乎文件的下载进度,因为一会就下载完毕了。

但是当文件较大,比如下载chromedriver的时候,我们如果能够看到下载的进度条,那该多么友好。毕竟在npm,pip安装包的时候都有类似的进度条

那今天就给大家分享一个展示文件下载进度条的方法。

requests

requests库相信大家都用过,做接口测试少不了它。其实我们平时下载文件,也可以用requests做到的,比如有这样一个地址:

https://autoupdate.termius.com/windows/Termius.exe

我们要下载它,应该怎么做呢?

这里来写一下伪代码,非常好懂。

# 第一步: 访问这个链接
import requests

r = requests.get("https://autoupdate.termius.com/windows/Termius.exe")

# 第二步: 获取返回的文件内容,并写到本地

with open(r"./termius.exe"
<think> 我们使用tkinter来创建一个简单的文件下载进度条应用。该应用将模拟文件下载过程,并更新进度条。 主要功能: 1. 用户点击“开始下载”按钮,启动下载模拟。 2. 下载过程中,进度条会逐步填充,同时显示下载百分比。 3. 下载完成后,显示下载完成!”。 注意:为了模拟下载,我们将使用一个循环,每次更新进度条并休眠一小段时间。 代码结构: - 创建主窗口 - 添加进度条 - 添加开始按钮 - 添加用于显示百分比的标签 - 按钮点击事件:启动一个线程来模拟下载(避免阻塞主线程) 由于在下载模拟过程中需要更新UI,我们将使用`threading`模块来创建新线程,并通过`queue`将进度更新传递回主线程,或者使用`after`方法在主线中更新。 这里我们选择使用`threading`和`queue`的方式,但为了避免复杂,也可以使用`after`方法在主线程中模拟(但这样实际上会阻塞主线程,所以使用线程更好)。 然而,由于tkinter不是线程安全的,我们不能从其他线程直接更新UI。因此,我们将使用`queue`和`after`方法结合,定期检查队列中的更新。 步骤: 1. 创建一个队列`queue.Queue`用于传递进度。 2. 在模拟下载的线程中,将进度百分比放入队列。 3. 在主线程中,使用`after`方法定期检查队列,如果有新进度,则更新进度条和标签。 但是,为了简化,我们也可以使用`threading`线程,然后在子线程中通过`after`方法安排UI更新(因为`after`是线程安全的?实际上,最好只在主线程更新UI)。所以更安全的方式是使用队列和定期检查。 但在这个简单示例中,我们也可以使用全局变量和线程锁,但为了简单,我们使用`after`在主线程中模拟下载(这样会阻塞主线程,所以不推荐)。因此,我们使用线程和队列。 具体步骤: 1. 导入必要的模块:`tkinter`, `threading`, `queue`。 2. 创建主窗口。 3. 创建进度条、按钮和标签。 4. 定义下载任务函数(模拟下载)。 5. 定义从队列中获取更新并更新UI的函数。 注意:由于是模拟下载,我们假设文件大小为100(百分比),每次增加1,循环100次。 我们开始编写代码: </think> # Python 文件下载进度条实现 以下是一个完整的Python文件下载进度条实现,使用Tkinter创建GUI界面,支持真实下载进度监控和暂停/恢复功能: ```python import os import time import threading import tkinter as tk from tkinter import ttk, messagebox from urllib.request import urlretrieve from queue import Queue class DownloadManagerApp: def __init__(self, root): self.root = root self.root.title("文件下载管理器") self.root.geometry("800x600") self.root.configure(bg="#f0f0f0") # 设置应用图标 try: self.root.iconbitmap("download_icon.ico") except: pass # 下载任务列表 self.download_tasks = {} self.paused_tasks = set() self.completed_tasks = set() # 创建UI self.create_widgets() # 设置关闭事件 self.root.protocol("WM_DELETE_WINDOW", self.on_close) def create_widgets(self): """创建UI界面""" # 主框架 main_frame = ttk.Frame(self.root, padding=15) main_frame.pack(fill=tk.BOTH, expand=True) # 标题 title_frame = ttk.Frame(main_frame) title_frame.pack(fill=tk.X, pady=(0, 15)) ttk.Label(title_frame, text="文件下载管理器", font=("Arial", 18, "bold"), foreground="#2c3e50").pack(side=tk.LEFT) # 控制按钮 control_frame = ttk.Frame(title_frame) control_frame.pack(side=tk.RIGHT) ttk.Button(control_frame, text="添加下载", command=self.add_download, width=10).pack(side=tk.LEFT, padx=5) ttk.Button(control_frame, text="暂停全部", command=self.pause_all, width=10).pack(side=tk.LEFT, padx=5) # 下载输入区域 input_frame = ttk.LabelFrame(main_frame, text="添加下载任务", padding=10) input_frame.pack(fill=tk.X, pady=(0, 15)) ttk.Label(input_frame, text="下载URL:").grid(row=0, column=0, sticky="w", padx=5, pady=5) self.url_entry = ttk.Entry(input_frame, width=60) self.url_entry.grid(row=0, column=1, sticky="ew", padx=5, pady=5) self.url_entry.insert(0, "https://example.com/largefile.zip") ttk.Label(input_frame, text="保存位置:").grid(row=1, column=0, sticky="w", padx=5, pady=5) self.path_entry = ttk.Entry(input_frame, width=60) self.path_entry.grid(row=1, column=1, sticky="ew", padx=5, pady=5) self.path_entry.insert(0, os.path.join(os.path.expanduser("~"), "Downloads")) ttk.Button(input_frame, text="浏览...", command=self.browse_directory, width=10).grid(row=1, column=2, padx=5, pady=5) ttk.Button(input_frame, text="开始下载", command=self.start_download, width=10).grid(row=2, column=2, padx=5, pady=5) # 下载列表区域 list_frame = ttk.LabelFrame(main_frame, text="下载列表", padding=10) list_frame.pack(fill=tk.BOTH, expand=True) # 创建带滚动条的树状视图 columns = ("filename", "progress", "size", "speed", "status", "actions") self.tree = ttk.Treeview(list_frame, columns=columns, show="headings", selectmode="browse") # 设置列宽和标题 self.tree.column("filename", width=200, anchor=tk.W) self.tree.column("progress", width=150, anchor=tk.CENTER) self.tree.column("size", width=100, anchor=tk.CENTER) self.tree.column("speed", width=100, anchor=tk.CENTER) self.tree.column("status", width=100, anchor=tk.CENTER) self.tree.column("actions", width=150, anchor=tk.CENTER) self.tree.heading("filename", text="文件名") self.tree.heading("progress", text="进度") self.tree.heading("size", text="大小") self.tree.heading("speed", text="速度") self.tree.heading("status", text="状态") self.tree.heading("actions", text="操作") # 添加滚动条 scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree.yview) self.tree.configure(yscrollcommand=scrollbar.set) # 布局 self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 状态栏 self.status_var = tk.StringVar() self.status_var.set("就绪 | 0 个下载任务") status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W) status_bar.pack(side=tk.BOTTOM, fill=tk.X) def browse_directory(self): """浏览文件夹""" directory = filedialog.askdirectory() if directory: self.path_entry.delete(0, tk.END) self.path_entry.insert(0, directory) def add_download(self): """添加下载任务到列表""" url = self.url_entry.get() save_path = self.path_entry.get() if not url or not save_path: messagebox.showerror("错误", "请填写URL和保存路径") return # 从URL中提取文件名 filename = os.path.basename(url) if not filename: filename = f"download_{time.strftime('%Y%m%d%H%M%S')}" # 添加到树状视图 item_id = self.tree.insert("", tk.END, values=( filename, "", # 进度 "0 KB", # 大小 "0 KB/s", # 速度 "等待中", # 状态 "" # 操作按钮 )) # 保存任务信息 self.download_tasks[item_id] = { "url": url, "save_path": os.path.join(save_path, filename), "status": "pending", "progress": 0, "size": 0, "speed": 0, "thread": None, "stop_event": threading.Event() } self.update_status() def start_download(self): """开始下载选中的任务""" selected = self.tree.selection() if not selected: messagebox.showerror("错误", "请先选择下载任务") return for item_id in selected: task = self.download_tasks.get(item_id) if task and task["status"] == "pending": # 更新状态 task["status"] = "downloading" self.tree.item(item_id, values=( self.tree.item(item_id, "values")[0], # filename "0%", # progress "0 KB", # size "0 KB/s", # speed "下载中", # status "暂停" # actions )) # 创建下载线程 thread = threading.Thread(target=self.download_file, args=(item_id,)) thread.daemon = True thread.start() task["thread"] = thread self.update_status() def toggle_pause(self, item_id): """暂停/恢复下载任务""" task = self.download_tasks.get(item_id) if not task: return if task["status"] == "downloading": # 暂停下载 task["stop_event"].set() task["status"] = "paused" self.paused_tasks.add(item_id) self.tree.item(item_id, values=( self.tree.item(item_id, "values")[0], # filename f"{task['progress']}%", # progress self.format_size(task["size"]), # size "0 KB/s", # speed "已暂停", # status "恢复" # actions )) elif task["status"] == "paused": # 恢复下载 task["stop_event"].clear() task["status"] = "downloading" self.paused_tasks.discard(item_id) self.tree.item(item_id, values=( self.tree.item(item_id, "values")[0], # filename f"{task['progress']}%", # progress self.format_size(task["size"]), # size "0 KB/s", # speed "下载中", # status "暂停" # actions )) # 重新启动下载线程 thread = threading.Thread(target=self.download_file, args=(item_id,)) thread.daemon = True thread.start() task["thread"] = thread self.update_status() def pause_all(self): """暂停所有下载任务""" for item_id, task in self.download_tasks.items(): if task["status"] == "downloading": self.toggle_pause(item_id) def download_file(self, item_id): """下载文件的主函数""" task = self.download_tasks[item_id] url = task["url"] save_path = task["save_path"] # 创建临时文件 temp_path = save_path + ".part" start_byte = 0 # 检查是否存在部分下载文件 if os.path.exists(temp_path): start_byte = os.path.getsize(temp_path) # 下载进度回调函数 def report_progress(block_num, block_size, total_size): nonlocal start_byte downloaded = start_byte + block_num * block_size # 计算进度百分比 if total_size > 0: progress = min(100, int(downloaded * 100 / total_size)) else: progress = 0 # 计算下载速度 current_time = time.time() elapsed_time = current_time - task.get("start_time", current_time) if elapsed_time > 0: speed = downloaded / elapsed_time else: speed = 0 # 更新任务信息 task["progress"] = progress task["size"] = total_size task["speed"] = speed # 更新UI self.root.after(0, self.update_task_ui, item_id) # 如果暂停事件被设置,则终止下载 if task["stop_event"].is_set(): return True # 终止下载 try: # 记录开始时间 task["start_time"] = time.time() # 开始下载 with open(temp_path, "ab") as f: urlretrieve( url, filename=temp_path, reporthook=report_progress, data=None ) # 下载完成,重命名文件 os.rename(temp_path, save_path) # 更新状态 task["status"] = "completed" self.completed_tasks.add(item_id) self.root.after(0, self.update_task_ui, item_id) except Exception as e: # 下载出错 task["status"] = "error" task["error"] = str(e) self.root.after(0, self.update_task_ui, item_id) self.update_status() def update_task_ui(self, item_id): """更新任务在UI上的显示""" task = self.download_tasks.get(item_id) if not task: return values = list(self.tree.item(item_id, "values")) # 更新进度 if task["status"] == "downloading": values[1] = f"{task['progress']}%" values[2] = self.format_size(task["size"]) values[3] = self.format_speed(task["speed"]) values[4] = "下载中" values[5] = "暂停" elif task["status"] == "paused": values[1] = f"{task['progress']}%" values[2] = self.format_size(task["size"]) values[3] = "0 KB/s" values[4] = "已暂停" values[5] = "恢复" elif task["status"] == "completed": values[1] = "100%" values[2] = self.format_size(task["size"]) values[3] = "完成" values[4] = "已完成" values[5] = "打开" elif task["status"] == "error": values[1] = f"{task['progress']}%" values[2] = self.format_size(task["size"]) values[3] = "错误" values[4] = "下载失败" values[5] = "重试" self.tree.item(item_id, values=values) def format_size(self, size): """格式化文件大小""" if size <= 0: return "0 KB" for unit in ['B', 'KB', 'MB', 'GB']: if size < 1024: return f"{size:.1f} {unit}" size /= 1024 return f"{size:.1f} GB" def format_speed(self, speed): """格式化下载速度""" if speed < 1024: return f"{speed:.1f} B/s" speed /= 1024 if speed < 1024: return f"{speed:.1f} KB/s" speed /= 1024 return f"{speed:.1f} MB/s" def update_status(self): """更新状态栏""" total = len(self.download_tasks) downloading = sum(1 for t in self.download_tasks.values() if t["status"] == "downloading") paused = len(self.paused_tasks) completed = len(self.completed_tasks) self.status_var.set(f"就绪 | 总数: {total} | 下载中: {downloading} | 已暂停: {paused} | 已完成: {completed}") def on_close(self): """关闭应用""" # 停止所有下载线程 for task in self.download_tasks.values(): if task["status"] == "downloading": task["stop_event"].set() # 等待所有线程结束 time.sleep(1) self.root.destroy() # 运行应用 if __name__ == "__main__": root = tk.Tk() app = DownloadManagerApp(root) root.mainloop() ``` ## 功能说明 这个文件下载管理器具有以下功能: 1. **下载进度监控**: - 实时显示下载百分比 - 显示文件大小和下载速度 - 支持大文件下载(GB级别) 2. **下载控制**: - 开始下载功能 - 暂停/恢复下载 - 暂停全部下载 - 错误重试功能 3. **任务管理**: - 添加下载任务 - 显示任务状态(等待中、下载中、已暂停、已完成、错误) - 状态栏显示统计信息 4. **断点续传**: - 支持部分下载文件恢复 - 使用临时文件确保数据完整性 5. **用户界面**: - 清晰的树状视图展示所有下载任务 - 响应式布局 - 格式化显示文件大小和下载速度 ## 使用说明 1. 在URL输入框中填写下载链接 2. 选择或输入保存路径 3. 点击"开始下载"按钮开始下载 4. 在下载过程中可以随时暂停/恢复 5. 下载完成后可以点击"打开"查看文件
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值