scrapy值图片下载管道以及保存本地
前言
对于图片下载,在scrapy框架中提供了专门下载的Pipeline,即ImagesPipeline这个是定义好的。但是对于我们来说,他的局限性很大,所以基本上我们需要重写一个Pipeline。怎么局限性?
内置的ImagesPipeline
会默认读取Item的image_urls字段,并认为该字段是一个列表形式,它会遍历Item的image_urls
字段,然后取出每个URL进行图片下载。而我们业务逻辑往往不是这样。
实现
setting.py设置图片保存路径
# 图片存储 IMAGES_STORE = './images'
自定义Pipeline并且重写ImagesPipeline方法
from scrapy.exceptions import DropItem from scrapy.pipelines.images import ImagesPipeline class ImagePipeline(ImagesPipeline): def file_path(self, request, response=None, info=None): item = request.meta['item'] url = request.url file_name = item['imagename'] + '/' + url.split('/')[-1] # imagename为博主定义的 这个可以更改为你在item传入值 return file_name def get_media_requests(self, item, info): if item['img']: # 这里假定img为需要下载的图片链接 实际按需更改 yield scrapy.Request(item['img'], meta={'item': item}) else: return item def item_completed(self, results, item, info): image_path = [x['path'] for ok, x in results if ok] if not image_path: raise DropItem("Item contains no images") item['img'] = image_path return item
setting.py文件引入ImagePipeline管道
# 引入ImagePipeline管道 ITEM_PIPELINES = { 'xxxxx.pipelines.ImagePipeline': 300, # 300表示优先级,按照自己实际逻辑先后执行顺序 }
说明
- get_media_requests() 它的第一个参数item是爬取生成的Item对象。我们将它的url字段取出来,然后直接生成Request对象。此Request加入到调度队列,等待被调度,执行下载。
- file_path() 它的第一个参数request就是当前下载对应的Request对象。这个方法用来返回保存的文件名,直接将图片链接的最后一部分当作文件名即可。它利用split()函数分割链接并提取最后一部分,返回结果。这样此图片下载之后保存的名称就是该函数返回的文件名。
- item_completed() 它是当单个Item完成下载时的处理方法。因为并不是每张图片都会下载成功,所以我们需要分析下载结果并剔除下载失败的图片。如果某张图片下载失败,那么我们就不需保存此Item到数据库。该方法的第一个参数results就是该Item对应的下载结果,它是一个列表形式,列表每一个元素是一个元组,其中包含了下载成功或失败的信息。这里我们遍历下载结果找出所有成功的下载列表。如果列表为空,那么该Item对应的图片下载失败,随即抛出异常DropItem,该Item忽略。否则返回该Item,说明此Item有效。
项目实战
Python基于Scrapy爬取www.rkpass.cn题目