利用Python實(shí)現(xiàn)一個(gè)帶進(jìn)度條的URL批量下載工具(含GUI界面)
效果

功能亮點(diǎn)
- 支持從
.xlsx文件讀取 URL 列表 - 批量下載,支持失敗重試日志
- 支持自定義保存目錄和子文件夾
- 帶有下載進(jìn)度條和實(shí)時(shí)狀態(tài)提示
- 全 GUI 操作,無(wú)需命令行
- 支持文件名自動(dòng)提取,無(wú)需手動(dòng)命名
用到的依賴庫(kù)
以下是該項(xiàng)目中用到的第三方庫(kù):
pip install requests pandas openpyxl
openpyxl 是 pandas.read_excel 在讀取 .xlsx 文件時(shí)默認(rèn)依賴的后端。
項(xiàng)目結(jié)構(gòu)拆解與說(shuō)明
提取工具邏輯:如何從 URL 獲取文件名
from urllib.parse import urlparse
def extract_filename_from_url(url):
path = urlparse(url).path
filename = os.path.basename(path)
return filename if filename else str(uuid.uuid4())
- 使用
urlparse提取路徑,再用os.path.basename獲取文件名; - 若鏈接無(wú)文件名(比如以
/結(jié)尾),則使用 UUID 作為備選。
下載邏輯:requests 下載 + 失敗捕獲
def download_file(url, folder_path):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
filename = extract_filename_from_url(url)
save_path = os.path.join(folder_path, filename)
with open(save_path, 'wb') as f:
f.write(response.content)
return True
except:
return False
- 使用
requests.get()獲取內(nèi)容; - 若出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤或 404,則返回 False,并記錄。
下載控制與進(jìn)度條更新
def start_download_with_progress(...):
...
def process_next(index):
...
# 下載成功/失敗計(jì)數(shù)
# 寫入失敗日志
# 更新進(jìn)度條 + 狀態(tài)文字
# after(100, ...) 避免阻塞 GUI
- 使用
progress_bar.after()模擬異步,防止主線程卡死; - 實(shí)時(shí)更新進(jìn)度條和狀態(tài)標(biāo)簽;
- 下載失敗寫入
download_fail.log,便于事后處理。
GUI 界面設(shè)計(jì)與交互邏輯
from tkinter import ...
- 使用 Tkinter 實(shí)現(xiàn)圖形界面;
- 包括:文件選擇按鈕、路徑輸入、保存子目錄輸入、進(jìn)度條、狀態(tài)文字、下載按鈕等;
- 綁定
Entry的<KeyRelease>事件實(shí)現(xiàn)路徑預(yù)覽實(shí)時(shí)更新; - 使用
ttk.Progressbar實(shí)現(xiàn)可視化進(jìn)度條。
界面示例(啟動(dòng)后):

使用說(shuō)明
- 準(zhǔn)備一個(gè)
.xlsx文件,第一列為 URL 列,第一行可為表頭; - 啟動(dòng)程序,點(diǎn)擊“選擇 Excel 文件”按鈕;
- 設(shè)置保存目錄與子文件夾名稱;
- 點(diǎn)擊“開始下載”,等待進(jìn)度條完成;
- 下載失敗的 URL 會(huì)記錄在
download_fail.log文件中。
實(shí)用建議
- 遇到下載失敗,可以手動(dòng)查看
download_fail.log并嘗試重試;
源碼
import os
import uuid
import requests
import pandas as pd
from datetime import datetime
from urllib.parse import urlparse
from tkinter import Tk, Label, Button, filedialog, messagebox, Entry, StringVar, Frame
from tkinter import ttk
# 獲取當(dāng)前時(shí)間默認(rèn)文件夾名
def get_default_folder_name():
return datetime.now().strftime('%Y%m%d%H%M')
# 提取 URL 文件名
def extract_filename_from_url(url):
path = urlparse(url).path
filename = os.path.basename(path)
return filename if filename else str(uuid.uuid4())
# 單個(gè)下載邏輯
def download_file(url, folder_path):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
filename = extract_filename_from_url(url)
save_path = os.path.join(folder_path, filename)
with open(save_path, 'wb') as f:
f.write(response.content)
return True
except:
return False
# 下載并更新 UI 進(jìn)度
def start_download_with_progress(urls, save_path, fail_log_path, progress_bar, status_label, start_button):
total = len(urls)
success = 0
fail = 0
def process_next(index):
nonlocal success, fail
if index >= total:
status_label.config(text=f"? 下載完成,成功 {success} 個(gè),失敗 {fail} 個(gè)")
start_button.config(state='normal')
return
url = urls[index]
ok = download_file(url, save_path)
if ok:
success += 1
else:
fail += 1
with open(fail_log_path, 'a', encoding='utf-8') as f:
f.write(url + '\n')
percent = int(((index + 1) / total) * 100)
progress_bar['value'] = percent
status_label.config(text=f"進(jìn)度:{percent}% | 成功:{success} 失?。簕fail}")
progress_bar.update()
# 延遲調(diào)用下一項(xiàng),避免 UI 卡死
progress_bar.after(100, lambda: process_next(index + 1))
process_next(0)
# 下載啟動(dòng)邏輯
def start_download(selected_file, folder_name_var, base_path_var, full_path_label_var,
progress_bar, status_label, start_button):
if not selected_file:
messagebox.showwarning("警告", "請(qǐng)先選擇 Excel 文件")
return
folder_name = folder_name_var.get().strip() or get_default_folder_name()
base_path = base_path_var.get().strip() or os.getcwd()
save_path = os.path.join(base_path, folder_name)
os.makedirs(save_path, exist_ok=True)
full_path_label_var.set(f"保存路徑:{save_path}")
try:
df = pd.read_excel(selected_file, usecols=[0])
urls = df.iloc[:, 0].astype(str).str.strip()
urls = urls[urls != ''] # 過濾空字符串
urls = urls.tolist()
if not urls:
messagebox.showinfo("提示", "未檢測(cè)到有效 URL")
return
# 清空失敗記錄
failed_log_path = os.path.join(save_path, 'download_fail.log')
with open(failed_log_path, 'w', encoding='utf-8') as f:
pass
progress_bar['maximum'] = 100
progress_bar['value'] = 0
progress_bar.pack(pady=10)
status_label.pack()
start_button.config(state='disabled')
start_download_with_progress(urls, save_path, failed_log_path,
progress_bar, status_label, start_button)
except Exception as e:
messagebox.showerror("錯(cuò)誤", f"下載過程中發(fā)生錯(cuò)誤:{e}")
# 文件選擇
def choose_file(selected_file_var, file_label):
file_path = filedialog.askopenfilename(filetypes=[("Excel 文件", "*.xlsx")])
if file_path:
selected_file_var.set(file_path)
file_label.config(text=f"已選擇文件:{os.path.basename(file_path)}")
# 保存路徑選擇
def select_directory(base_path_var, folder_name_var, full_path_label_var):
selected = filedialog.askdirectory()
if selected:
base_path_var.set(selected)
update_full_path_label(folder_name_var, base_path_var, full_path_label_var)
# 路徑標(biāo)簽更新
def update_full_path_label(folder_name_var, base_path_var, full_path_label_var):
folder_name = folder_name_var.get().strip() or get_default_folder_name()
base_path = base_path_var.get().strip() or os.getcwd()
full_path_label_var.set(f"保存路徑:{os.path.join(base_path, folder_name)}")
# 主界面
def create_gui():
root = Tk()
root.title("URL 批量下載工具 作者:XMYX-0")
root.geometry("620x460")
selected_file_var = StringVar()
folder_name_var = StringVar(value=get_default_folder_name())
base_path_var = StringVar(value=os.getcwd())
full_path_label_var = StringVar()
# UI 元素
Label(root, text="1. 選擇包含 URL 的 Excel 文件(.xlsx)", font=("微軟雅黑", 11)).pack(pady=10)
file_label = Label(root, text="尚未選擇文件", font=("微軟雅黑", 10), fg="gray")
file_label.pack()
Button(root, text="選擇 Excel 文件", font=("微軟雅黑", 10),
command=lambda: choose_file(selected_file_var, file_label)).pack(pady=5)
Label(root, text="2. 設(shè)置保存目錄", font=("微軟雅黑", 11)).pack(pady=10)
Label(root, text="保存子目錄名稱:", font=("微軟雅黑", 10)).pack()
folder_entry = Entry(root, textvariable=folder_name_var, font=("微軟雅黑", 10), width=35)
folder_entry.pack()
path_frame = Frame(root)
path_frame.pack(pady=10)
Label(path_frame, text="保存路徑:", font=("微軟雅黑", 10)).grid(row=0, column=0, padx=5)
path_entry = Entry(path_frame, textvariable=base_path_var, font=("微軟雅黑", 10), width=35)
path_entry.grid(row=0, column=1)
Button(path_frame, text="瀏覽", command=lambda: select_directory(base_path_var, folder_name_var, full_path_label_var)).grid(row=0, column=2, padx=5)
update_full_path_label(folder_name_var, base_path_var, full_path_label_var)
Label(root, textvariable=full_path_label_var, font=("微軟雅黑", 9), fg="gray").pack()
progress_bar = ttk.Progressbar(root, length=400)
status_label = Label(root, text="", font=("微軟雅黑", 10))
start_button = Button(root, text="? 開始下載", font=("微軟雅黑", 12), bg="#4CAF50", fg="white",
command=lambda: start_download(
selected_file_var.get(),
folder_name_var,
base_path_var,
full_path_label_var,
progress_bar,
status_label,
start_button))
start_button.pack(pady=20)
folder_entry.bind("<KeyRelease>", lambda e: update_full_path_label(folder_name_var, base_path_var, full_path_label_var))
path_entry.bind("<KeyRelease>", lambda e: update_full_path_label(folder_name_var, base_path_var, full_path_label_var))
Label(root, text="注意:Excel 的第一行為標(biāo)題,從第二行開始讀取 URL", font=("微軟雅黑", 9), fg="gray").pack(pady=10)
root.mainloop()
if __name__ == "__main__":
create_gui()
以上就是利用Python實(shí)現(xiàn)一個(gè)帶進(jìn)度條的URL批量下載工具的詳細(xì)內(nèi)容,更多關(guān)于Python URL批量下載工具的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python實(shí)現(xiàn)合成多張圖片到PDF格式
在日常生活中,經(jīng)常會(huì)遇到需要提交身份證正反面證明資料的情況,而且這些網(wǎng)站大部分只接受pdf格式,這時(shí)候我們就需要把身份證正反面兩張圖片合成為一個(gè)pdf文件。本文將為大家提供用Python實(shí)現(xiàn)這一要求的方法,需要的可以參考一下2022-02-02
如何使用PyTorch實(shí)現(xiàn)自由的數(shù)據(jù)讀取
這篇文章主要給大家介紹了關(guān)于如何使用PyTorch實(shí)現(xiàn)自由的數(shù)據(jù)讀取的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-03-03
python之pygame模塊實(shí)現(xiàn)飛機(jī)大戰(zhàn)完整代碼
這篇文章主要為大家詳細(xì)介紹了python之pygame模塊實(shí)現(xiàn)飛機(jī)大戰(zhàn)完整代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11
python中常用排序操作sort方法和sorted函數(shù)的使用超詳細(xì)講解(內(nèi)置模板代碼!)
這篇文章主要介紹了Python中的排序方法,包括sort()方法和sorted()函數(shù)的使用,sort()方法用于列表,對(duì)原列表進(jìn)行排序,文章還提供了一些排序案例模板代碼,以解決實(shí)際問題,需要的朋友可以參考下2025-02-02
python復(fù)制列表時(shí)[:]和[::]之間有什么區(qū)別
這篇文章主要給大家介紹了關(guān)于python復(fù)制列表時(shí)[:]和[::]之間有什么區(qū)別的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10

