• 十八、scrapy内置媒体(图片和文件)下载方式


    scrapy为下载的item中包含的文件提供了一个可重用的item pipeline(scrapy.pipelines.media.MediaPipeline),这些Pipeline有些共同的方法和结构。

    MediaPipeline共同实现了以下特性:

      (1)避免重新下载最近已经下载过的数据

      (2)指定存储的位置和方式

    ImagesPipeline还提供了额外的特性:

      (1)将所有下载的图片转换成通用的格式(JPG)和模式(RGB)

      (2)缩略图生成

      (3)检查图像的宽/高,确保它们满足最小限制

    MediaPipeline去重的方式:

      (1)MediaPipeline会为当前安排好的要下载的图片保留一个内部队列,并将那些到达的包含相同图片的项目连接到该队列中,避免多次下载几个item共享的同一图片

    1、使用FilesPipeline的工作流程

      1、在一个爬虫里,抓取一个item,把其中文件的url放入file_urls组内

      2、Item从爬虫内返回,进入item pipeline

      3、当item进入filespipeline,file_urls组内的url将被Scrapy的调度器和下载器安排下载。Item会在这个特定的管道阶段保持"Locker"的状态,直到完成文件的下载(或者未完成下载而失败)

      4、当文件下载完成后,另一个字段(files)将被更新到结构中。这个组将包含一个字典列表,其中包括下载文件的信息,如下载路径、源抓取地址和文件的校验码(checksum)。files列表文件顺序将和源file_urls组保持一致。当某个文件下载失败,将会记录下错误信息,文件将不会出现在files组内。

    2、使用FilesPipeline

      1、在settings.py文件的ITEM_PIPELINES中添加一条“scrapy.pipelines.files.FilesPipeline”:1

      2、在item中添加两个字段:

        (1)file_urls = scrapy.Field()

        (2)files = scrapy.Field()

      3、在settings.py文件中添加:

        (1)FILES_STORE = "./files"  # 下载路径

        (2)FILES_FILES_FIELD = 'file_urls'  # 文件url所在的item字段

        (3)FILES_RESULT_FIELD = "files"  # 文件结果信息所在的item字段

      4、在settings.py中的可选设置

        (1)FILES_EXPIRES = 30   # 30天过期  

        (2)IMAGES_THUMBS  = {

            "small":(50,70),

            "big":(270,270),

          }

          IMAGES_THUMBS能制作缩略图,并设置缩略图尺寸大小。

          IMAGES_EXPIRES = 30   设置文件过期时间

          IMAGES_MIN_HEIGHT和IMAGES_MIN_WIDTH来设置图片的最小高和宽

    3、示例

      1、目录结构

        

         图片名称是图片下载链接由scrapy自行按经过SHA1哈希后的值

        

         image_urls存在目标url,images存放返回结果

      2、items.py代码

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

      3、settings.py代码

    BOT_NAME = 'tiantangtupian'
    
    SPIDER_MODULES = ['tiantangtupian.spiders']
    NEWSPIDER_MODULE = 'tiantangtupian.spiders'
    
    LOG_LEVEL = "WARNING"
    
    
    # Obey robots.txt rules
    ROBOTSTXT_OBEY = False
    
    
    # Configure item pipelines
    # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
    ITEM_PIPELINES = {
        'tiantangtupian.pipelines.TiantangtupianPipeline': 300,
        'scrapy.pipelines.images.ImagesPipeline':1,
    }
    IMAGES_STORE = './Images'
    IMAGES_URLS_FIELD = 'image_urls'
    IMAGES_RESULT_FIELD = 'images'

      4、pipelines.py

    class TiantangtupianPipeline:
        def process_item(self, item, spider):
            print(item)
            return item

      5、main.py  

    class TttpSpider(scrapy.Spider):
        name = 'tttp'
        allowed_domains = ['ivsky.com']
        start_urls = ['https://www.ivsky.com/tupian/ziranfengguang/index_1.html']
    
        def parse(self, response):
            li_list = response.xpath('//ul[@class="ali"]/li')
            for li in li_list:
                item = TiantangtupianItem()
                href = li.xpath('.//img/@src').extract()
                item['href'] = parse.urljoin(base=response.url,url=href[0] if href else None)
                item['image_urls'] = [parse.urljoin(base=response.url,url=href[0] if href else None)]
                yield item

    4、定制自己的FilesPipeline

      需要继承FilesPipeline或者ImagesPipeline,重写get_media_requests和item_completed()方法。

      1、get_media_requests(item,info)方法

        需要重写get_media_requests()方法,并对各个图片url返回一个Request

        ```

        def get_media_requests(self,item,info):

          for image_url in item['image_urls']:

            yield scrapy.Request(image_url)

        ```

        当这些请求由管道处理完成后,结果results将以2-元素的元组列表形式传送到item_completed()方法中

        

         success是一个布尔值,当图片成功下载时为True,失败时为False

        url是图片下载的url

        path是图片存储的路径

        checksum是图片内容MD5 hash

      2、item_completed(results,items,info)方法

        当一个单独项目中的所有图片请求完成时,ImagesPipeline.item_completed()方法将被调用。

        results参数是get_media_requests下载完成之后返回的结果。

        item_completed()方法需要返回一个输出(可以按需要返回或丢弃项目),该item将被送到随后的ItemPipelines。

        ```

        from scrapy.exceptions import DropItem

        def item_completed(self,results,item,info):

          image_paths = [x['path'] for ok,x in results if ok]  # 遍历取url

          if not image_paths:

            raise DropItem("Item contains no images")

          item['image_urls'] = image_paths  #去掉没有完成下载的图片链接

          return item

        ```

      3、示例

        注意:重写的itempipeline需要在settings中注册才能使用。

    from scrapy.pipelines.images import ImagesPipeline
    from scrapy.exceptions import DropItem
    import scrapy
    from pprint import pprint
    
    class TiantangtupianPipeline:
        def process_item(self, item, spider):
            print(item)
            return item
    
    
    class MyImagesPipeline(ImagesPipeline):
        def get_media_requests(self,item,info):
            for image_url in item['image_urls']:
                yield scrapy.Request(url=image_url)
    
        def item_completed(self, results, item, info):
            print("*"*50)
            pprint(results)
            print("*" * 50)
            print("-"*20)
            image_path = [x['path'] for ok,x in results if ok]
            if not image_path:
                raise DropItem("Item contains no images")
            item['image_urls'] = image_path
            return item

      

  • 相关阅读:
    Ext4文件系统架构分析(二)
    Ext4文件系统架构分析(一)
    STL容器与拷贝构造函数
    左值、右值与右值引用
    C++ 11右值引用
    读书笔记_Effective_C++_条款二十五: 考虑写出一个不抛出异常的swap函数
    《Effective C++》item25:考虑写出一个不抛异常的swap函数
    CC++ vector 构造函数 & 析构函数
    复制构造函数 与 赋值函数 的区别
    a++与++a
  • 原文地址:https://www.cnblogs.com/nuochengze/p/13143928.html
Copyright © 2020-2023  润新知