Scrapy框架之利用ImagesPipeline下载图片

作者: 大黄大黄大黄 | 来源:发表于2017-05-30 16:48 被阅读1941次

    1.ImagesPipeline简介

    Scrapy用ImagesPipeline类提供一种方便的方式来下载和存储图片。

    特点:

    • 将下载图片转换成通用的JPG和RGB格式
    • 避免重复下载
    • 缩略图生成
    • 图片大小过滤

    2.ImagesPipeline工作流程

    当使用图片管道 ImagePipeline,典型的工作流程如下:

    • 在一个爬虫里,你抓取一个项目,把其中图片的URL放入image_urls组内。
    • 项目从爬虫内返回,进入项目管道。
    • 当项目进入ImagePipeline, image_urls组内的URLs将被Scrapy的调度器和下载器安排下载(这意味着调度器和中间件可以复用),当优先级更高,会在其他页面被抓取前处理. 项目会在这个特定的管道阶段保持"locker"的状态,直到完成图片的下载(或者由于某些原因未完成下载)。
    • 当图片下载完, 另一个组(images)将被更新到结构中,这个组将包含一个字典列表,其中包括下载图片的信息,比如下载路径,源抓取地址(从image_urls组获得)和图片的校验码. images列表中的图片顺序将和源image_urls组保持一致.如果某个图片下载失败,将会记录下错误信息,图片也不会出现在images组中。

    3.操作过程

    项目目录结构:

    这里写图片描述

    <font size=5>要想成功爬取图片,需要经过以下几个步骤:

    (1) 在items.py中添加image_urls、images和image_paths字段,代码如下:

    class DoubanImgsItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        image_urls = Field()
        images = Field()
        image_paths = Field()
    

    (2)在settings.py中设置条件和属性,代码如下:

    # Configure item pipelines
    # See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
    
    # ImagePipeline的自定义实现类
    ITEM_PIPELINES = {
        'douban_imgs.pipelines.DoubanImgDownloadPipeline': 300,
    }
    #设置图片下载路径
    IMAGES_STORE = 'D:\\doubanimgs'
    # 过期天数
    IMAGES_EXPIRES = 90  #90天内抓取的都不会被重抓
    

    (3)在spiders/download_douban.py中书写ImageSpider的代码:

    # coding=utf-8
    from scrapy.spiders import Spider
    import re
    from scrapy import Request
    from ..items import DoubanImgsItem
    
    
    class download_douban(Spider):
        name = 'download_douban'
    
        default_headers = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept-Encoding': 'gzip, deflate, sdch, br',
            'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
            'Cache-Control': 'max-age=0',
            'Connection': 'keep-alive',
            'Host': 'www.douban.com',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
        }
    
        def __init__(self, url='1638835355', *args, **kwargs):
            self.allowed_domains = ['douban.com']
            self.start_urls = [
                'http://www.douban.com/photos/album/%s/' % (url)]
            self.url = url
            # call the father base function
    
            # super(download_douban, self).__init__(*args, **kwargs)
    
        def start_requests(self):
    
            for url in self.start_urls:
                yield Request(url=url, headers=self.default_headers, callback=self.parse)
    
        def parse(self, response):
            list_imgs = response.xpath('//div[@class="photolst clearfix"]//img/@src').extract()
            if list_imgs:
                item = DoubanImgsItem()
                item['image_urls'] = list_imgs
                yield item
    
    

    (4)在pipelines.py中自定义ImagePipeline代码:

    # -*- coding: utf-8 -*-
    
    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
    from scrapy.pipelines.images import ImagesPipeline
    from scrapy.exceptions import DropItem
    from scrapy import Request
    from scrapy import log
    
    
    class DoubanImgsPipeline(object):
        def process_item(self, item, spider):
            return item
    
    
    class DoubanImgDownloadPipeline(ImagesPipeline):
        default_headers = {
            'accept': 'image/webp,image/*,*/*;q=0.8',
            'accept-encoding': 'gzip, deflate, sdch, br',
            'accept-language': 'zh-CN,zh;q=0.8,en;q=0.6',
            'cookie': 'bid=yQdC/AzTaCw',
            'referer': 'https://www.douban.com/photos/photo/2370443040/',
            'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
        }
    
        def get_media_requests(self, item, info):
            for image_url in item['image_urls']:
                self.default_headers['referer'] = image_url
                yield Request(image_url, headers=self.default_headers)
    
        def item_completed(self, results, item, info):
            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
    
    

    在自定义ImagePipeline代码中,作为重要的是要重载get_media_requests(self, item, info)item_completed(self, results, item, info)这两个函数。

    • get_media_requests(self,item, info):

    ImagePipeline根据image_urls中指定的url进行爬取,可以通过get_media_requests为每个url生成一个Request。如:

    for image_url in item['image_urls']:
                self.default_headers['referer'] = image_url
                yield Request(image_url, headers=self.default_headers)
    
    
    • item_completed(self, results, item, info):

    图片下载完毕后,处理结果会以二元组的方式返回给item_completed()函数。这个二元组定义如下:

    (success, image_info_or_failure)

    其中,第一个元素表示图片是否下载成功;第二个元素是一个字典。如:

     def item_completed(self, results, item, info):
            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
    

    4.爬取结果

    运行结果如下:

    这里写图片描述

    下载成功以后,你就会在刚才设置的保存图片的路径里看到下载完成的图片:IMAGES_STORE = 'D:\doubanimgs'

    这里写图片描述

    5.扩展

    默认情况下,使用ImagePipeline组件下载图片的时候,图片名称是以图片URL的SHA1值进行保存的。

    如:
    图片URL:http://www.example.com/image.jpg
    SHA1结果:3afec3b4765f8f0a07b78f98c07b83f013567a0a
    则图片名称:3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg

    如果想进行更改,请参考:使用scrapy框架的ImagesPipeline下载图片如何保持原文件名呢?


    相关文章

      网友评论

        本文标题:Scrapy框架之利用ImagesPipeline下载图片

        本文链接:https://www.haomeiwen.com/subject/tcurfxtx.html