Scrapy将图片保存至刚入库记录ID命名文件夹的问题求助
问题解决与说明
一、Scrapy执行顺序说明
Scrapy的Pipeline执行顺序由ITEM_PIPELINES中的数值决定,数值越小优先级越高。默认如果ImagesPipeline优先级更高,会先下载图片再入库;但你需要用入库后的书籍ID存储图片,所以必须让数据库Pipeline(你的BookPipeline)优先级更高,先完成入库并把数据库生成的ID写入item,再执行图片下载。
二、自定义图片存储Pipeline修复
你的CustomImageNamePipeline存在几处问题,以下是修正后的完整方案:
1. 补全缺失的导入
代码漏了hashlib和to_bytes的导入,这会导致逻辑无法正常运行:
import scrapy import hashlib import os from scrapy.pipelines.images import ImagesPipeline from scrapy.utils.python import to_bytes # 补全该导入
2. 调整Pipeline优先级与入库逻辑
- 修改
my_spider.py中的custom_settings,让数据库Pipeline先执行:
custom_settings = { 'ITEM_PIPELINES': { 'project.pipelines.BookPipeline': 100, # 先执行入库,获取数据库生成的书籍ID 'project.pipelines.CustomImageNamePipeline': 200 # 后执行图片下载 }, 'IMAGES_STORE': 'book_images', 'LOG_LEVEL': 'DEBUG' # 开启DEBUG日志,方便排查图片下载问题 }
- 在
BookPipeline的process_item方法中,完成数据库插入后,将生成的书籍ID写入item:
class BookPipeline: def process_item(self, item, spider): # 替换为你的实际数据库插入逻辑,假设插入后返回生成的ID book_id = self.insert_to_db(item) item['book_id'] = book_id # 将数据库ID存入item,供图片Pipeline使用 return item
3. 修正图片存储路径逻辑
修改CustomImageNamePipeline,使用入库后的book_id作为文件夹名:
class CustomImageNamePipeline(ImagesPipeline): def get_media_requests(self, item, info): # 传递入库后的书籍ID到请求meta中 return [scrapy.Request(url, meta={'book_id': item['book_id']}) for url in item.get('image_urls', [])] def file_path(self, request, response=None, info=None, *, item=None): url = request.url media_guid = hashlib.sha1(to_bytes(url)).hexdigest() media_ext = os.path.splitext(url)[1] # 按书籍ID创建子文件夹存储图片 return f'{request.meta["book_id"]}/{media_guid}{media_ext}'
4. 原代码失效原因
- 缺失必要导入,导致代码执行失败但未抛出明显错误(受日志级别影响)
- Pipeline优先级错误,图片下载先于入库,此时没有可用的数据库ID
- 未开启DEBUG日志,无法查看图片请求的调度和下载状态
三、验证步骤
- 确保
book_images目录存在(Scrapy会自动创建子文件夹) - 运行爬虫后,检查
book_images下是否按书籍ID生成对应文件夹,图片是否正确存入 - 查看DEBUG日志,确认图片请求是否被正常调度和下载
内容的提问来源于stack exchange,提问作者user984621
相关产品推荐
相关产品推荐

