爬虫小白:11.scrapy框架(六) _媒体管道

2020-08-05 15:48:03 浏览数 (1)

一、媒体管道(ImagesPipeline)是什么?

scrapy提供了专门下载的PIpeline,包含文件下载和图片下载。

二、为什么要有媒体管道?

简化操作,比如存储等。当然我们可以进行重写。

  1. 将下载图片转换成通用的JPG和RGB格式
  2. 避免重复下载
  3. 缩略图生成
  4. 图片大小过滤
  5. 异步下载

三、媒体管道的使用

1)使用

工作流程:
  1. 爬取一个Item,将图片的URLs放入image_urls字段
  2. 从Spider返回的Item,传递到Item Pipeline
  3. 当Item传递到ImagePipeline,将调用Scrapy 调度器和下载器完成image_urls中的url的调度和下载。
  4. 图片下载成功结束后,图片下载路径、url和校验和等信息会被填充到images字段中。
代码语言:javascript复制
1、items.py定义特殊字段名 :
 #内置的ImagePipeline会默认读取Item的image_urls字段,item.py 中只能写image_urls字段 
 image_urls = scrapy.Field()  #固定

2、处理pipelines.py ,分为两种:
 1、自定义pipeline,且让 类 继承ImagesPipeline,优势在于可以重写ImagePipeline类中的实现方法。
 2、直接使用ImagePipeline类,简单但不够灵活。

 方法一:
 #这是自定义,优势在于可以重写ImagePipeline类中的实现方法,可以根据情况对照片进行分类;
    '''
     首先要复写父类的两个方法,一个是get_midia_requests(),构建request请求,然后交由下载器下载,第二个是item_completed(),当下载完毕后,默认会调用该方法,我们只需注意第二个results参数,他是一个由二元元祖组成的list,第一个值是一个布尔类型的值,用于判断图片是否下载成功,第二个值是关于图片的下载信息。
    '''
    from scrapy.pipelines.images import ImagesPipeline
    from scrapy.exceptions import DropItem
    from scrapy import Request
    
    class 类名(ImagesPipeline):   #切记得继承ImagesPipeline
        def get_media_requests(self, item, info):
            for url in item['image_urls']:
                yield Request(url)
                
        def item_completed(self, results, item, info):
            item['images'] = [x for ok, x in results if ok]
            return item
        
        def process_item(self,item,spider):
            with open() as f:
                f.write()
            return item 


 方法二:
 #在管道得开启 'scrapy.pipelines.images.ImagesPipeline' 这是媒体基础管道,可以试一下。且直接使用  ImagePipeline类,虽简单但不够灵活;所有的图片都是保存在 full文件夹下,而且图片名。

3、 配置settings中的ITEM_PIPELINES:
 ITEM_PIPELINES={
 #方法一:  管道开启
 '项目名.piplines.自定义类名':1 , #后面数字1让它马上调用。

 #方法二: 这是图片基础管道,scrapy写的,直接开启它就行了。
 'scrapy.pipelines.images.ImagesPipeline': 1 
 }

4、媒体管道的一些设置:
 在settings.py里添加,如IMAGES_STORE = 'IMG'    #设置图片存储位置,这个必须得设</pre>

直接使用ImagePipeline类 , 所有的图片都是保存在 full文件夹下:

直接使用ImagePipeline类存储结果.png

2)媒体管道的一些设置:

代码语言:javascript复制
在settings中添加就可以了
​
ITEM_PIPELINES = {‘scrapy.pipelines.images.ImagesPipeline’: 1}   #启用
FILES_STORE = ‘/path/to/valid/dir’      #文件管道存放位置
IMAGES_STORE = ‘/path/to/valid/dir’      #图片管道存放位置
FILES_URLS_FIELD = ‘field_name_for_your_files_urls’              #自定义文件url字段
FILES_RESULT_FIELD = ‘field_name_for_your_processed_files’       #自定义结果字段
IMAGES_URLS_FIELD = ‘field_name_for_your_images_urls’            #自定义图片url字段
IMAGES_RESULT_FIELD = ‘field_name_for_your_processed_images’     #结果字段
FILES_EXPIRES = 90                   #文件过期时间 默认90天
IMAGES_EXPIRES = 90                  #图片过期时间 默认90天
IMAGES_THUMBS = {‘small’: (50, 50), ‘big’:(270, 270)}          #缩略图尺寸
IMAGES_MIN_HEIGHT = 110              #过滤最小高度
IMAGES_MIN_WIDTH = 110               #过滤最小宽度
MEDIA_ALLOW_REDIRECTS = True      #是否重定向</pre>

四、按例:爬取百度图片

代码语言:javascript复制
1、item.py文件:定义item字段
import scrapy
class ImgPipelineItem(scrapy.Item):
 # define the fields for your item here like:
 # name = scrapy.Field()
 image_urls =  scrapy.Field()    #只要使用媒体管道,这个字段是固定设置的

​
2、spider.py文件:编写爬虫文件,解析源码,得到图片的url下载路径
import scrapy
import re
from ..items import ImgPipelineItem
​
class MediaSpider(scrapy.Spider):
 name = 'media'
 # allowed_domains = ['www.baidu.com']
 start_urls = ['https://image.baidu.com/search/index?tn=baiduimage&ct=201326592&lm=-1&cl=2&ie=gb18030&word=�˰���&fr=ala&ala=1&alatpl=adress&pos=0&hs=2&xthttps=111111']
​
 def parse(self, response):
 img_urls = re.findall('"thumbURL":"(.*?)"',response.text)[0:-1]
 # print(img_urls)
 item = ImgPipelineItem()
 item['image_urls'] = img_urls
 yield item

3、pipelines.py文件:对item里的数据进行处理,这里是调用调度器和下载器下载图片。 
       若直接使用ImagePipeline类 , 所以这里不用处理。

       自定义:
    import os
    import scrapy
    class ImgPipelinePipeline(ImagesPipeline):
    # def get_media_requests(self, item, info):
    def get_media_requests(self, item, info):
        for file_url in item['image_urls']:
            print("**********")
            yield scrapy.Request(file_url)

    def item_completed(self, results, item, info):
        # image_paths = [x['path'] for ok, x in results if ok]
        image_paths=[]
        for ok,x in results:
            if ok:
                image_paths.append(x['path'])
        print(image_paths)
        # if not image_paths:
        #     raise DropItem("Item contains no files")
        # item['image_paths'] = image_paths
        # return item

    #     return [scrapy.Request(x) for x in item.get(self.images_urls_field, [])]
    #
    # pass
    # num = 0
    # def process_item(self, item, spider):
    #     self.num =1
    #     with open(str(self.num) ".jpg","wb") as f:
    #         f.write(item["content"])
    #     return item

0 人点赞