使用Scrapy ImagesPipeline下载图片时遇OSError错误求助
解决Scrapy ImagesPipeline的
OSError: cannot identify image file错误 这个错误我之前做图片爬取项目时碰到过好几次,核心问题基本都是下载的内容不是有效的图片文件,要么是反爬页面、要么是数据损坏,或是依赖库识别出了问题。下面分几种常见情况给你排查和解决思路:
1. 先确认下载的内容到底是什么
很多时候网站会返回反爬页面(比如验证码、403提示)、404页面的HTML代码,而非真实图片。你可以先做个简单的调试验证:
解决方法:自定义Pipeline查看响应内容
继承ImagesPipeline,在处理流程里加入日志和临时文件保存,看看下载的内容到底是什么:
from scrapy.pipelines.images import ImagesPipeline import logging import os class DebugImagesPipeline(ImagesPipeline): def media_downloaded(self, response, request, info): # 先检查响应状态码 if response.status != 200: logging.warning(f"⚠️ 图片下载失败,状态码: {response.status},URL: {request.url}") return None # 跳过该无效图片 # 把响应内容保存成临时文件,手动查看 temp_dir = "temp_image_check" os.makedirs(temp_dir, exist_ok=True) temp_file = os.path.join(temp_dir, f"{hash(request.url)}.bin") with open(temp_file, "wb") as f: f.write(response.body) logging.info(f"📝 临时文件已保存: {temp_file}") # 继续执行原有的图片处理流程 return super().media_downloaded(response, request, info)
然后在settings.py里把这个自定义Pipeline替换默认的ImagesPipeline,运行爬虫后去temp_image_check目录看文件:如果是HTML文本,说明网站反爬了;如果是乱码但不是图片,大概率是请求头不对。
2. 调整请求头,绕过反爬限制
很多网站会检查User-Agent、Referer字段,没有正确设置的话会返回非图片内容:
解决方法:在Spider里设置真实请求头
发送图片请求时,加上浏览器的User-Agent和图片所在页面的Referer:
def parse(self, response): # 假设从页面提取到图片URL image_url = response.css("img::attr(src)").get() if image_url: yield scrapy.Request( image_url, meta={"image_urls": [image_url]}, # 传给ImagesPipeline用 headers={ "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", "Referer": response.url # 必须是图片所在页面的URL }, dont_filter=True, # 避免重复请求被过滤 callback=self.parse_image # 可选,单独处理图片响应 )
如果还是不行,可以试试添加浏览器里复制的Cookie字段(登录后的Cookie),有些网站需要登录才能访问图片。
3. 检查Pillow库的兼容性
ImagesPipeline依赖Pillow来识别图片格式,如果Pillow版本过低,可能不支持WebP等新型格式,或是安装时缺失了格式支持:
解决方法:更新或重新安装Pillow
- 先更新到最新版本:
pip install --upgrade pillow
- 如果还是无法识别WebP格式,需要安装带WebP支持的Pillow:
# Ubuntu/Debian先安装系统依赖 sudo apt-get install libwebp-dev # 然后重新安装Pillow pip install --force-reinstall pillow
4. 处理图片数据损坏的情况
网络波动可能导致下载的图片数据不完整,这时候可以开启重试机制:
解决方法:在settings.py里配置重试
# 开启重试中间件 DOWNLOADER_MIDDLEWARES = { 'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550, } # 设置重试次数 RETRY_TIMES = 3 # 设置需要重试的状态码 RETRY_HTTP_CODES = [500, 502, 503, 504, 400, 403, 404]
内容的提问来源于stack exchange,提问作者Little Steward
相关产品推荐
相关产品推荐

