使用Python requests下载图片偶发损坏无法打开的最优解决方案是什么
核心原因说明
你当前代码的问题是缺少异常校验逻辑:只要请求发出去不管返回的是正确图片内容、还是服务器错误页/反爬拦截页,都会直接写入本地文件;同时stream模式下如果网络中断,可能只写入了部分图片内容,最终导致文件损坏无法打开。
可直接使用的优化代码
import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def download_image(url, save_path, timeout=30, max_retry=3): # 配置重试策略,应对网络波动、临时服务错误 session = requests.session() retry_strategy = Retry( total=max_retry, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504] ) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("https://", adapter) session.mount("http://", adapter) # 加通用请求头,避免反爬拦截 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } try: res = session.get(url, headers=headers, stream=True, timeout=timeout) # 强制校验请求状态,非200直接抛出异常 res.raise_for_status() # 校验内容长度,避免下载不全 total_size = int(res.headers.get("content-length", 0)) downloaded_size = 0 with open(save_path, "wb") as f: # 逐块写入,适配大文件下载同时统计下载量 for chunk in res.iter_content(chunk_size=8192): if chunk: f.write(chunk) downloaded_size += len(chunk) # 非零内容长度场景下校验完整性 if total_size > 0 and downloaded_size != total_size: raise IOError(f"下载不完整,预期大小:{total_size}字节,实际下载:{downloaded_size}字节") # 可选:本地校验图片合法性,需要提前安装Pillow库:pip install pillow # from PIL import Image # with Image.open(save_path) as img: # img.verify() return True except Exception as e: # 下载失败自动清理损坏的本地文件 import os if os.path.exists(save_path): os.remove(save_path) print(f"下载失败:{str(e)}") return False # 调用示例 download_image("你的图片URL", "foo.png")
关键优化点说明
- 自动重试:针对网络波动、服务器临时错误场景自动重试,避免单次请求失败导致内容异常
- 状态校验:只有请求返回200状态码才会写入文件,避免把错误页内容当图片存储
- 完整性校验:比对实际下载大小和响应头标注的文件大小,避免网络中断导致的半截文件
- 反爬适配:添加正常浏览器的UA头,避免网站返回拦截页面导致文件损坏
- 异常回滚:下载失败自动删除损坏的残留文件,避免无效文件占空间
内容的提问来源于stack exchange,提问作者Hasti
相关产品推荐
相关产品推荐

