使用Python批量下载大文件时遇到不完整下载及连接报错的问题求助
使用Python批量下载大文件时遇到不完整下载及连接报错的问题求助
嗨,我最近碰到个批量下载文件的麻烦事,想请大伙帮忙支支招:
我需要从指定URL下载16000+个文件(单个最大1GB),格式涵盖.pdf、.ppt、.doc、.docx、.zip、.jpg、.iso等。自己用requests写了代码,但遇到两个头疼的问题:
- 有时候能正常下载,但经常只下了26KB就停了,文件完全不完整
- 时不时会弹出错误:
[Errno 10054] An existing connection was forcibly closed by the remote host
我最开始写的代码是这样的:
def download_file(s): for row in sheet.iter_rows(min_row=2): try: url = row[6].value # 从Excel里读取URL # 发送GET请求 response = s.get(url) if response.status_code == 200: with open(save_path, 'wb') as file: file.write(response.content) except Exception as e: print(f"Error: {e}") if __name__ == "__main__": with requests.session() as s: res = s.post(login_url, data=login_data) download_file(s)
后来我也尝试过用shutil分块下载,还有手动迭代分块的方式,但问题还是没解决:
import shutil with requests.get(url, stream=True) as r: with open(local_filename, 'wb') as f: shutil.copyfileobj(r.raw, f)
response = requests.get(url, stream=True) with open(book_name, 'wb') as f: for chunk in response.iter_content(1024 * 1024 * 2): f.write(chunk)
问题分析与解决方案
我来帮你捋捋问题根源,再给你一套更健壮的处理方案:
为什么会出现这些问题?
- 连接被强制关闭(Errno 10054):大概率是服务器检测到你批量请求的频率太高,触发了限流/反爬机制,直接断开了连接;也可能是网络波动导致连接中途中断。
- 文件下载不完整:一方面是连接中断后没有重试逻辑,只下载了部分内容就停止;另一方面,直接读取
response.content会把整个文件塞进内存,大文件很容易出问题,而且如果服务器没有返回完整响应,也会导致文件残缺。
改进后的代码
这套代码加入了重试机制、浏览器请求头模拟、文件完整性校验、请求频率控制,专门针对批量大文件下载优化:
import requests import time import os from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def create_robust_session(): # 创建带重试策略的session,应对连接错误和服务器异常 session = requests.Session() retry_strategy = Retry( total=3, # 最多重试3次 backoff_factor=1, # 重试间隔依次为1s, 2s, 4s status_forcelist=[429, 500, 502, 503, 504], # 遇到这些状态码自动重试 allowed_methods=["GET"] # 只对GET请求重试 ) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("https://", adapter) session.mount("http://", adapter) # 模拟浏览器请求头,避免被识别为爬虫 session.headers.update({ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" }) return session def download_single_file(session, url, save_path, chunk_size=2*1024*1024): # 跳过已存在的文件,避免重复下载 if os.path.exists(save_path): print(f"[{save_path}] 已存在,跳过") return try: # 发送请求,设置超时时间防止卡住 with session.get(url, stream=True, timeout=30) as response: response.raise_for_status() # 主动抛出HTTP错误(比如404、500) # 获取文件总大小(服务器返回的话) total_size = int(response.headers.get('content-length', 0)) downloaded_size = 0 with open(save_path, 'wb') as f: for chunk in response.iter_content(chunk_size=chunk_size): if chunk: # 过滤空块 f.write(chunk) downloaded_size += len(chunk) # 可选:打印下载进度 # print(f"[{save_path}] 已下载: {downloaded_size}/{total_size} bytes", end='\r') # 校验文件完整性 if total_size != 0 and downloaded_size != total_size: print(f"[{save_path}] 下载不完整,已删除残缺文件") os.remove(save_path) # 可选:这里可以再加一次重试 # download_single_file(session, url, save_path) else: print(f"[{save_path}] 下载完成") except Exception as e: print(f"[{url}] 下载失败: {str(e)}") # 删除可能存在的残缺文件 if os.path.exists(save_path): os.remove(save_path) if __name__ == "__main__": login_url = "你的登录地址" login_data = {"username": "你的用户名", "password": "你的密码"} # 假设sheet是你已读取好的Excel工作表对象(比如用openpyxl加载) # sheet = ... 请自行初始化Excel读取逻辑 with create_robust_session() as s: # 先确保登录成功 login_res = s.post(login_url, data=login_data) login_res.raise_for_status() print("登录成功") # 遍历Excel行批量下载 for row_num, row in enumerate(sheet.iter_rows(min_row=2), start=2): url = row[6].value if not url: print(f"第{row_num}行URL为空,跳过") continue # 从URL提取文件名,生成保存路径 filename = url.split('/')[-1] save_dir = "你的文件保存目录" os.makedirs(save_dir, exist_ok=True) # 确保保存目录存在 save_path = os.path.join(save_dir, filename) download_single_file(s, url, save_path) # 控制请求频率,避免触发服务器限流 time.sleep(1)
额外小贴士
- 日志记录:可以把下载失败的URL写入日志文件,方便后续批量重试或者手动处理
- 多线程优化:如果单线程下载太慢,可以用
concurrent.futures.ThreadPoolExecutor开少量线程(比如5-10个),但一定要配合time.sleep控制频率,别把服务器惹毛了 - 断点续传:对于1GB级的超大文件,可以实现断点续传——检查已下载文件的大小,发送
Range请求继续下载剩余部分 - 代理IP:如果你的IP被服务器封禁,可以考虑用代理池,但要注意代理的稳定性和合法性
备注:内容来源于stack exchange,提问作者user166013
相关产品推荐
相关产品推荐

