scrapy的快速入门(二)

下载及处理文件和图片
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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 141,649评论 20 608
  • Media Pipeline Scrapy为下载item中包含的文件(比如在爬取到产品时,同时也想保存对应的图片)...
    cnkai阅读 1,673评论 2 1
  • scrapy学习笔记(有示例版) 我的博客 scrapy学习笔记1.使用scrapy1.1创建工程1.2创建爬虫模...
    陈思煜阅读 8,807评论 5 42
  • 上一篇咱们讲解了Scrapy的工作机制和如何使用Scrapy爬取美女图片,而今天接着讲解Scrapy爬取美女图片,...
    qiye阅读 4,301评论 9 19
  • 又回到达州了,走在熟悉的街道,回想到爸爸,想到以前的时光,感觉爸爸的脸还在面前,难受
    叶增援阅读 24评论 0 0