• Scrapy学习篇(九)之文件与图片下载


    Media Pipeline

    Scrapy为下载item中包含的文件(比如在爬取到产品时,同时也想保存对应的图片)提供了一个可重用的 item pipelines . 这些pipeline有些共同的方法和结构(称之为media pipeline)。我们可以使用FilesPipeline和Images Pipeline来保存文件和图片,他们有以下的一些特点:

    • Files Pipeline
      • 避免重新下载最近已经下载过的数据
      • 指定存储路径
      FilesPipeline的典型工作流程如下:
      1. 在一个爬虫里,你抓取一个项目,把其中图片的URL放入 file_urls 组内。
      2. 项目从爬虫内返回,进入项目管道。
      3. 当项目进入 FilesPipeline,file_urls 组内的URLs将被Scrapy的调度器和下载器(这意味着调度器和下载器的中间件可以复用)安排下载,当优先级更高,会在其他页面被抓取前处理。项目会在这个特定的管道阶段保持“locker”的状态,直到完成文件的下载(或者由于某些原因未完成下载)。
      4. 当文件下载完后,另一个字段(files)将被更新到结构中。这个组将包含一个字典列表,其中包括下载文件的信息,比如下载路径、源抓取地址(从 file_urls 组获得)和图片的校验码(checksum)。 files 列表中的文件顺序将和源 file_urls 组保持一致。如果某个图片下载失败,将会记录下错误信息,图片也不会出现在 files 组中。
    • Images Pipeline
      • 避免重新下载最近已经下载过的数据
      • 指定存储路径
      • 将所有下载的图片转换成通用的格式(JPG)和模式(RGB)
      • 缩略图生成
      • 检测图像的宽/高,确保它们满足最小限制
      和FilesPipeline类似,除了默认的字段名不同,image_urls保存图片URL地址,images保存下载后的图片信息。当然,它还提供了一些拓展功能,比如图片的缩略图,过滤图片的尺寸。
      注意:你需要安装Pillow 库来实现以上的拓展功能。

    启用Media Pipeline

    要想使用media pipeline,你需要在设置添加一些必要的信息。

    # 同时启用图片和文件管道
    ITEM_PIPELINES = {
                      'scrapy.pipelines.images.ImagesPipeline': 1,
                      'scrapy.pipelines.files.FilesPipeline': 2,
                     }
    FILES_STORE = 'D:'  # 文件存储路径
    IMAGES_STORE = 'D' # 图片存储路径
    
    # 避免下载最近90天已经下载过的文件内容
    FILES_EXPIRES = 90
    # 避免下载最近30天已经下载过的图像内容
    IMAGES_EXPIRES = 30
    
    # 设置图片缩略图
    IMAGES_THUMBS = {
        'small': (50, 50),
        'big': (250, 250),
    }
    # 图片过滤器,最小高度和宽度,低于此尺寸不下载
    IMAGES_MIN_HEIGHT = 110
    IMAGES_MIN_WIDTH = 110

    你可能会好奇文件的命名,在当你启用media pipeline以后,
    它的默认命名方式是这样的,文件以它们URL的 SHA1 hash 作为文件名。
    例如,
    对下面的图片URL:http://www.example.com/image.jpg,
    其SHA1 hash 值为:3afec3b4765f8f0a07b78f98c07b83f013567a0a
    将被下载并存为下面的文件:<IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg

    扩展Media Pipeline

    下面我们以ImagesPipeline为例来自定义ImagesPipeline,需要重写以下两个方法:

    • get_media_requests(item, info)
      在工作流程中可以看到,管道会得到图片的URL并从项目中下载。为了这么做,你需要重写 get_media_requests() 方法,并对各个图片URL返回一个Request:

      def get_media_requests(self, item, info):
          for image_url in item['image_urls']:
              yield scrapy.Request(image_url)
      这些请求将被管道处理,当它们完成下载后,结果将以2元素的元组列表形式传送到 item_completed() 方法: 每个元组包含 (success, file_info_or_error):
      • success 是一个布尔值,当图片成功下载时为 True ,因为某个原因下载失败为False
      • file_info_or_error 是一个包含下列关键字的字典(如果成功为 True )或者出问题时为 Twisted Failure 。
        url - 文件下载的url。这是从 get_media_requests() 方法返回请求的url。
        path - 图片存储的路径(类似 IMAGES_STORE)
        checksum - 图片内容的 MD5 hash
        item_completed() 接收的元组列表需要保证与 get_media_requests() 方法返回请求的顺序相一致。下面是 results 参数的一个典型值:

        [(True,
          {'checksum': '2b00042f7481c7b056c4b410d28f33cf',
           'path': 'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg',
           'url': 'http://www.example.com/files/product1.jpg'}),
         (False,
          Failure(...))]

        该方法 必须返回每一个图片的URL。

    • item_completed(results, items, info)
      当一个单独项目中的所有图片请求完成时,例如,item里面一共有10个URL,那么当这10个URL全部下载完成以后,ImagesPipeline.item_completed() 方法将被调用。默认情况下, item_completed() 方法返回item。

    使用ImagesPipeline下载图片

    下面我们用上面学习到的知识来下载一些图片。
    我们以http://jandan.net/ooxx为例,把页面上的图片下载下来,并产生缩略图
    我们新建一个项目,名为jiandan,各个文件内容如下。

    • item.py
    import scrapy
    
    class JiandanItem(scrapy.Item):
        image_urls = scrapy.Field()#图片的链接
        images = scrapy.Field()
    • jiandan_spider.py
    import scrapy
    from jiandan.items import JiandanItem
    
    class jiandanSpider(scrapy.Spider):
        name = 'jiandan'
        start_urls = ["http://jandan.net/ooxx"]
    
        def parse(self, response):
    
            item = JiandanItem()
            item['image_urls'] = response.xpath('//img//@src').extract() #提取图片链接
            yield item
    • settings.py
    BOT_NAME = 'jiandan'
    
    SPIDER_MODULES = ['jiandan.spiders']
    NEWSPIDER_MODULE = 'jiandan.spiders'
    
    DEFAULT_REQUEST_HEADERS = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'en',
        'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
    }
    
    ITEM_PIPELINES = {
       'jiandan.pipelines.JiandanPipeline':1,
    }
    IMAGES_STORE='H:\jiandan'
    IMAGES_THUMBS = {
        'small': (50, 50),
        'big': (200, 200),
    }
    • pipelinse.py
    import scrapy
    from scrapy.exceptions import DropItem
    from scrapy.pipelines.images import ImagesPipeline   #内置的图片管道
    
    class JiandanPipeline(ImagesPipeline):#继承ImagesPipeline这个类
    
        def get_media_requests(self, item, info):
            for image_url in item['image_urls']:
                image_url = "http://" + image_url
                yield scrapy.Request(image_url)
    
    
    
        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")
            return item

    运行这个spider,你会发现,图片已经下载好了,如下图所示。


    图片内容你可以自己慢慢看。

  • 相关阅读:
    0152 日期对象Date:实例化,属性和方法,操作总毫秒数【时间戳】,案例
    0151 Math对象:random、round、floor、ceil、abs、max、min、随机整数、案例
    0150 内置对象概述、查阅MDN文档
    0149 遍历对象:for...in
    0148 JavaScript 的 new关键字
    0147 JavaScript创建对象的三种方式 之 构造函数
    0146 JavaScript创建对象的三种方式 之 new Object
    0145 JavaScript创建对象的三种方式 之 字面量:创建,访问对象的属性&方法,变量、属性、函数、方法总结
    0144 对象:相关概念、对象的优势
    0143 JavaScript预解析:概念、变量预解析、函数预解析、函数表达式声明函数问题、案例
  • 原文地址:https://www.cnblogs.com/lxbmaomao/p/10363381.html
Copyright © 2020-2023  润新知