美文网首页
scrapy的快速入门(二)

scrapy的快速入门(二)

作者: 王小鱼鱻 | 来源:发表于2017-10-21 11:37 被阅读90次

    下载及处理文件和图片
    Scrapy为下载item中包含的文件(比如在爬取到产品时,同时也想保存对应的图片)提供了一个可重用的 item pipelines . 这些pipeline有些共同的方法和结构(我们称之为media pipeline)。一般来说你会使用Files Pipeline或者 Images Pipeline。
    这两种pipeline都实现了以下特性:
    1、避免重新下载最近已经下载过的数据;
    2、指定存储媒体的位置(文件系统目录,Amazon S3 bucket)图像管道有一些额外的功能来处理图像;
    3、将所有下载的图片转换成通用的格式(JPG)和模式(RGB);
    4、缩略图生成;
    5、检测图像的宽/高,确保它们满足最小限制;

    这个管道也会为那些当前安排好要下载的图片保留一个内部队列,并将那些到达的包含相同图片的项目连接到那个队列中。 这可以避免多次下载几个项目共享的同一个图片。

    一、使用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
    当使用 ImagesPipeline ,典型的工作流程如下所示:
    1、在一个爬虫里,你抓取一个项目,把其中图片的URL放入 image_urls 组内。
    2、项目从爬虫内返回,进入项目管道。
    3、当项目进入 ImagesPipeline,image_urls 组内的URLs将被Scrapy的调度器和下载器(这意味着调度器和下载器的中间件可以复用)安排下载,当优先级更高,会在其他页面被抓取前处理。项目会在这个特定的管道阶段保持“locker”的状态,直到完成文件的下载(或者由于某些原因未完成下载)。
    4、当文件下载完后,另一个字段(images)将被更新到结构中。这个组将包含一个字典列表,其中包括下载文件的信息,比如下载路径、源抓取地址(从 image_urls 组获得)和图片的校验码(checksum)。 files 列表中的文件顺序将和源 image_urls 组保持一致。如果某个图片下载失败,将会记录下错误信息,图片也不会出现在 images 组中。

    使用ImagesPipeline非常类似于使用FilesPipeline,除了使用的默认字段名称不同:您使用image_urls作为项目的图像URL,并将填充图像字段以获取有关下载的图像的信息。
    使用ImagesPipeline进行图像文件的优点是您可以配置一些额外的功能,例如生成缩略图,并根据大小对图像进行过滤。
    Pillow 是用来生成缩略图,并将图片归一化为JPEG/RGB格式,因此为了使用图片管道,你需要安装这个库。 Python Imaging Library (PIL) 在大多数情况下是有效的,但众所周知,在一些设置里会出现问题,因此我们推荐使用 Pillow 而不是PIL。

    下面利用Images Pipeline爬取花瓣网下载想要的图片。

    1、新建一个工程,打开cmd,
    输入scrapy startproject huaban_imagepipeline

    新建工程
    这里的每个文件的含义上一篇文章scrapy的快速入门(一)已介绍过了,可以自行翻看之前的文章;
    2、定制item
    # -*- coding: utf-8 -*-
    
    # Define here the models for your scraped items
    #
    # See documentation in:
    # http://doc.scrapy.org/en/latest/topics/items.html
    
    import scrapy
    
    
    class HuabanImagepipelineItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        image_urls = scrapy.Field()  # 图片的链接
        images = scrapy.Field()
    
    

    3、爬虫的关键部分——spiders
    在spiders的文件下新建一个huaban_spider.py

    import scrapy
    from ..items import HuabanImagepipelineItem
    from scrapy.conf import settings #从settings文件中导入Cookie,这里也可以from scrapy.conf import settings.COOKIE
    import requests
    import json
    import math
    from scrapy.http import Request
    
    
    class HuabanSpider(scrapy.Spider):
        name = "huabanSpider"
        allowed_domains = ['huaban.com']
        query = "张敏"
        start_urls = ['http://huaban.com/search/?q=%s' % query]
        # 带着Cookie向网页发请求
        cookie = settings['COOKIE']
        #利用抓包获取必要的参数,这里我用的是postman
        headers = {
            'cookies': 'uid=21839587; sid=8ckMdriGQD28yFUdISQIqykQwGn.KuxyNV3X2l9A87ShUPD1LLauT6PZdgi4AUm44wZqFXs;',
            'X-Requested-With': 'XMLHttpRequest',
        }
    
        html = requests.get(start_urls[0], headers = headers).content
        infos = json.loads(html)
        totalpage = math.ceil(int(infos['pin_count'])/20) #总的页数
    
        #构造每页的链接
        def parse(self, response):
            for i in range(1, int(self.totalpage) + 1):
                page = str(i)
                urls = ["http://huaban.com/search/?q={}&page={}".format(self.query, page)]
                for url in urls:
                    yield Request(url, headers = self.headers, meta = {'key':url}, callback=self.parse_image)
    
        #构造每个图片下载的链接
        def parse_image(self, response):
            item = HuabanImagepipelineItem()
            pin_html = requests.get(response.meta['key'], headers=self.headers).content
            infos = json.loads(pin_html)
            pins = infos['pins']
            url_list = []
            for pin in pins:
                key_id = pin['file']['key']
                download_url = "http://img.hb.aicdn.com/" + key_id + "_fw658"
                url_list.append(download_url)
            item['image_urls'] = url_list
            yield item
    
    

    4、图片管道pipeline

    # -*- 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.exceptions import DropItem
    from scrapy.pipelines.images import ImagesPipeline
    import scrapy
    
    
    class HuabanImagepipelinePipeline(ImagesPipeline):
    
        def get_media_requests(self, item, info):  # 重写ImagesPipeline   get_media_requests方法
            '''
            :param item:
            :param info:
            :return:
            在工作流程中可以看到,
            管道会得到文件的URL并从项目中下载。
            为了这么做,你需要重写 get_media_requests() 方法,
            并对各个图片URL返回一个Request:
            '''
            for image_url in item['image_urls']:
                yield scrapy.Request(image_url)
    
        def item_completed(self, results, item, info):
            '''
            当一个单独项目中的所有图片请求完成时(要么完成下载,要么因为某种原因下载失败),
             item_completed() 方法将被调用。
            '''
            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)这两个函数。
    1)get_media_requests(self,item, info):
    ImagePipeline根据image_urls中指定的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, 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
    

    5、在settings.py中设置条件和属性

    # -*- coding: utf-8 -*-
    import random
    from useragent import Agent  #导入请求头,防止被ban
    BOT_NAME = 'huabanSpider'
    
    SPIDER_MODULES = ['huaban_imagepipeline.spiders']
    NEWSPIDER_MODULE = 'huaban_imagepipeline.spiders'
    
    ITEM_PIPELINES = {
        'huaban_imagepipeline.pipelines.HuabanImagepipelinePipeline': 1,
    }
    
    
    # Crawl responsibly by identifying yourself (and your website) on the user-agent
    
    
    USER_AGENT = '%s'%random.choice(Agent.user_agent)
    #USER_AGENT = 'huaban_imagepipeline (+http://www.yourdomain.com)'
    
    # Obey robots.txt rules
    ROBOTSTXT_OBEY = True
    
    # Configure maximum concurrent requests performed by Scrapy (default: 16)
    CONCURRENT_REQUESTS = 100
    
    # Retry many times since proxies often fail
    RETRY_TIMES = 10
    # Retry on most error codes since proxies fail for different reasons
    RETRY_HTTP_CODES = [500, 503, 504, 400, 403, 404, 408]
    
    # Configure a delay for requests for the same website (default: 0)
    # See http://scrapy.readthedocs.org/en/latest/topics/settings.html#download-delay
    # See also autothrottle settings and docs
    DOWNLOAD_DELAY = 0.2
    # The download delay setting will honor only one of:
    #CONCURRENT_REQUESTS_PER_DOMAIN = 16
    #CONCURRENT_REQUESTS_PER_IP = 16
    
    # Disable cookies (enabled by default)禁止使用cookie
    COOKIES_ENABLED = False
    #图片存储路径
    IMAGES_STORE='E:\\spider\\pictures\\huaban\\zm'
    #存储缩略图
    IMAGES_THUMBS = {#缩略图的尺寸,设置这个值就会产生缩略图
        'small': (50, 50),
        'big': (200, 200),
    }
    

    运行结果:
    会生成2个文件夹,

    图片

    full:原图,
    thumbs:缩略图,包含2个文件夹:big、small,

    缩略图 Paste_Image.png

    相关文章

      网友评论

          本文标题:scrapy的快速入门(二)

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