十八、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内置媒体(图片和文件)下载方式

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

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

     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()方法中

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

     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

相关推荐