Python批量下载脚本出现ZeroDivisionError(除零错误)求助
解决
urllib下载进度钩子中的ZeroDivisionError问题 嘿,我看到你在批量下载文件时遇到了这个烦人的ZeroDivisionError,其实这是个很常见的小坑——当文件太小、下载速度极快(比如命中本地缓存)时,计算耗时的duration会接近0,甚至直接等于0,导致除法运算出错。另外我还注意到你代码里有几个变量名不一致的问题,也会导致额外的错误,一起帮你搞定了。
问题根源拆解
- 除以0错误:当下载完成得太快时,
time.time() - start_time的结果会小于0.01秒(甚至为0),直接用它做除数就触发了ZeroDivisionError - 变量名错误:函数参数里的
block_size和total_size,后面写成了blockSize和totalSize,这会导致NameError - 全局变量风险:用全局
start_time在批量下载时会出现状态混乱,比如前一个文件的时间会干扰下一个文件的进度计算
修复后的完整代码
import urllib.request import json import sys import time with open('finalsinbin.json') as json_data: items = json.load(json_data) def reporthook(count, block_size, total_size, start_time): if count == 0: return duration = time.time() - start_time # 核心修复:避免除以0,当耗时极短时直接显示速度为0 if duration < 0.01: speed = 0 progress_size = count * block_size else: progress_size = count * block_size speed = int(progress_size / (1024 * duration)) # 处理服务器不返回文件大小的情况 if total_size <= 0: percent = 100 else: percent = min(int(progress_size * 100 / total_size), 100) # 优化显示格式,让进度条更直观 mb = progress_size / (1024 * 1024) sys.stdout.write("\r...%d%%, %.1f MB, %d KB/s, %.1f seconds passed" % (percent, mb, speed, duration)) sys.stdout.flush() def batch(startAt, stopAt): a = 0 for i in items: a += 1 if a < startAt or a > stopAt: continue num = i['id'] url = i['url'] typ = i['type'] urlfinal = f"{url}/{num}{typ}" filename = f"{num}{typ}" print(f'[{a}] Descargando el archivo {filename}...') # 为每个文件单独初始化start_time,避免全局变量冲突 task_start_time = time.time() # 用lambda把当前任务的start_time传递给钩子函数 urllib.request.urlretrieve( urlfinal, filename, lambda count, bs, ts, st=task_start_time: reporthook(count, bs, ts, st) ) batch(1, 100)
关键改进说明
- 避免除以0:增加了
duration < 0.01的判断,当下载耗时极短时直接显示速度为0,完美绕过除法错误 - 修复变量名问题:统一了
block_size和total_size的变量名,再也不会出现NameError - 移除全局变量:每个下载任务都有自己独立的
task_start_time,通过lambda传递给钩子函数,批量下载时状态不会混乱 - 兼容未知文件大小:有些服务器不会返回文件总大小,此时直接显示100%完成,避免计算出错
- 优化显示效果:MB和耗时都保留1位小数,进度条看起来更清晰;用f-string替换老旧的格式化方式,代码更简洁
- 鲁棒性提升:即使遇到极快的下载任务,脚本也能稳定运行
额外实用建议
考虑到你要下载4365个文件,还有几个可以优化的点:
- 添加异常捕获:给
urlretrieve加上try-except块,处理网络中断、文件权限等错误,避免单个文件下载失败导致整个批量任务终止 - 实现断点续传:如果下载中断,下次可以从已下载的位置继续,不用重新下载整个文件(
urllib本身不支持,需要自己处理请求头的Range字段) - 控制下载并发:同步下载4000多个文件会很慢,可以用
threading开几个线程并发下载(注意不要开太多,避免被服务器封禁)
内容的提问来源于stack exchange,提问作者pedrovn
相关产品推荐
相关产品推荐

