使用Scrapy自带ImagePipeline下载图片
示例代码
# 启用scrapy自带的图片下载pipeline
ITEM_PIPELINES = {
'scrapy.pipelines.images.ImagesPipeline': 1,
}
IMAGES_URLS_FIELD = "front_image_url" # 设置item中作为图片下载链接的item字段
project_dir = os.path.abspath(os.path.dirname(__file__))
IMAGES_STORE = os.path.join(project_dir, 'images') # 设置图片存储路径
注意
- 默认的ImagePipeline要求接收的图片下载url字段为列表类型,如果不是列表类型将会报错。
- 使用默认ImagePipeline时可能会报这样的错误:ModuleNotFoundError: No module named ‘PIL’,原因是缺少一个pillow的库,通过pip install pillow命令下载即可
遇到的异常
- 图片下载字段为空异常且图片下载链接不规范
使用Scrapy自带ImagePipeline下载图片使用Scrapy自带ImagePipeline下载图片自定义ImagePipeline 使用Scrapy自带ImagePipeline下载图片使用Scrapy自带ImagePipeline下载图片自定义ImagePipeline
解决方案——重载ImagePipeline
有些文章没有封面图,也就不会有图片下载链接这个值,对应的item中的该字段也就为None,但我设置的没有匹配时默认为‘ ’。但是scrapy自带的ImagePipeline是默认认位每一个item中对应的图片链接字段都有正确可访问的图片链接。导致对于一些没有该链接的item下载图片是报错异常。解决方法是自定义ImagePipeline,重写其中的get_media_request()函数,这个函数用来遍历item中的图片下载链接字段,生成request,交给scrapy引擎下载图片。我在这个方法中添加了判断是否‘ ’ 的逻辑。
class CustomImagePipeline(ImagesPipeline):
def get_media_requests(self, item, info):
# 重写ImagesPipeline类的get_media_requests方法
# 实现:下载图片之前判断item对应字段的url是否为‘ ’,如果为‘’就跳过下载。
for url in item['cover_image_url']:
if url != '':
try:
yield Request(url=url)
except:
url = 'https:' + url
try:
yield Request(url=url)
except:
url = 'http:' + url
yield Request(url=url)
注意
在get_media_request()函数中生成的Request和在spider中使用的Requset是不一样的,这里的Request在from scrapy.http import Request这里,而spider中的Request在from scrapy.spider import Request
自定义ImagePipeline
示例代码
from scrapy.pipelines.images import ImagesPipeline
from scrapy.http import Request
from scrapy.exceptions import DropItem
class CustomImagePipeline(ImagesPipeline):
def file_path(self, request, response=None, info=None):
"""
重写ImagesPipeline类的file_path方法
实现:下载下来的图片命名是以校验码来命名的,该方法实现保持原有图片命名
:return: 图片路径
"""
image_guid = request.url.split('/')[-1] # 取原url的图片命名
return 'full/%s'% image_guid
def get_media_requests(self, item, info):
"""
重写ImagesPipeline类的get_media_requests方法
实现:下载图片之前判断item对应字段的url是否为‘’,如果为‘’就跳过下载。
"""
for url in item['cover_image_url']:
if url!= '':
yield Request(url=url)
def item_completed(self, results, item, info):
"""
将图片的本地路径赋值给item['image_paths']
:param results:下载结果,二元组定义如下:(success, image_info_or_failure)。
第一个元素表示图片是否下载成功;第二个元素是一个字典。
如果success=true,image_info_or_error词典包含以下键值对。失败则包含一些出错信息。
字典内包含*url:原始URL * path:本地存储路径 * checksum:校验码
:param item:
:param info:
:return:
"""
image_paths = [x['path'] for ok, x in results if ok]
if not image_paths:
raise DropItem("Item contains no images") # 如果没有路径则抛出异常
item['image_paths'] = image_paths
return item