下載及處理文件和圖片
Scrapy為下載item中包含的文件(比如在爬取到產(chǎn)品時彤委,同時也想保存對應的圖片)提供了一個可重用的 item pipelines . 這些pipeline有些共同的方法和結構(我們稱之為media pipeline)豌汇。一般來說你會使用Files Pipeline或者 Images Pipeline相恃。
這兩種pipeline都實現(xiàn)了以下特性:
1、避免重新下載最近已經(jīng)下載過的數(shù)據(jù)陕赃;
2肛响、指定存儲媒體的位置(文件系統(tǒng)目錄闪檬,Amazon S3 bucket)圖像管道有一些額外的功能來處理圖像;
3氛悬、將所有下載的圖片轉換成通用的格式(JPG)和模式(RGB)则剃;
4、縮略圖生成如捅;
5棍现、檢測圖像的寬/高,確保它們滿足最小限制镜遣;
這個管道也會為那些當前安排好要下載的圖片保留一個內(nèi)部隊列轴咱,并將那些到達的包含相同圖片的項目連接到那個隊列中。 這可以避免多次下載幾個項目共享的同一個圖片烈涮。
一朴肺、使用Files Pipeline
當使用 FilesPipeline ,典型的工作流程如下所示:
1坚洽、在一個爬蟲里戈稿,你抓取一個項目,把其中圖片的URL放入 file_urls 組內(nèi)讶舰。
2鞍盗、項目從爬蟲內(nèi)返回,進入項目管道跳昼。
3般甲、當項目進入 FilesPipeline,file_urls 組內(nèi)的URLs將被Scrapy的調度器和下載器(這意味著調度器和下載器的中間件可以復用)安排下載鹅颊,當優(yōu)先級更高敷存,會在其他頁面被抓取前處理。項目會在這個特定的管道階段保持“l(fā)ocker”的狀態(tài)堪伍,直到完成文件的下載(或者由于某些原因未完成下載)锚烦。
4、當文件下載完后帝雇,另一個字段(files)將被更新到結構中涮俄。這個組將包含一個字典列表,其中包括下載文件的信息尸闸,比如下載路徑彻亲、源抓取地址(從 file_urls 組獲得)和圖片的校驗碼(checksum)孕锄。 files 列表中的文件順序將和源 file_urls 組保持一致。如果某個圖片下載失敗苞尝,將會記錄下錯誤信息硫惕,圖片也不會出現(xiàn)在 files 組中。
二野来、使用圖像管道Images Pipeline
當使用 ImagesPipeline 恼除,典型的工作流程如下所示:
1、在一個爬蟲里曼氛,你抓取一個項目豁辉,把其中圖片的URL放入 image_urls 組內(nèi)。
2舀患、項目從爬蟲內(nèi)返回徽级,進入項目管道。
3聊浅、當項目進入 ImagesPipeline餐抢,image_urls 組內(nèi)的URLs將被Scrapy的調度器和下載器(這意味著調度器和下載器的中間件可以復用)安排下載,當優(yōu)先級更高低匙,會在其他頁面被抓取前處理旷痕。項目會在這個特定的管道階段保持“l(fā)ocker”的狀態(tài),直到完成文件的下載(或者由于某些原因未完成下載)顽冶。
4欺抗、當文件下載完后,另一個字段(images)將被更新到結構中强重。這個組將包含一個字典列表绞呈,其中包括下載文件的信息,比如下載路徑间景、源抓取地址(從 image_urls 組獲得)和圖片的校驗碼(checksum)佃声。 files 列表中的文件順序將和源 image_urls 組保持一致。如果某個圖片下載失敗倘要,將會記錄下錯誤信息圾亏,圖片也不會出現(xiàn)在 images 組中。
使用ImagesPipeline非常類似于使用FilesPipeline碗誉,除了使用的默認字段名稱不同:您使用image_urls作為項目的圖像URL召嘶,并將填充圖像字段以獲取有關下載的圖像的信息。
使用ImagesPipeline進行圖像文件的優(yōu)點是您可以配置一些額外的功能哮缺,例如生成縮略圖,并根據(jù)大小對圖像進行過濾甲喝。
Pillow 是用來生成縮略圖尝苇,并將圖片歸一化為JPEG/RGB格式,因此為了使用圖片管道,你需要安裝這個庫糠溜。 Python Imaging Library (PIL) 在大多數(shù)情況下是有效的淳玩,但眾所周知,在一些設置里會出現(xiàn)問題非竿,因此我們推薦使用 Pillow 而不是PIL蜕着。
下面利用Images Pipeline爬取花瓣網(wǎng)下載想要的圖片。
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向網(wǎng)頁發(fā)請求
cookie = settings['COOKIE']
#利用抓包獲取必要的參數(shù),這里我用的是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) #總的頁數(shù)
#構造每頁的鏈接
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)這兩個函數(shù)躲叼。
1)get_media_requests(self,item, info):
ImagePipeline根據(jù)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()函數(shù)。這個二元組定義如下:
(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 = {#縮略圖的尺寸,設置這個值就會產(chǎn)生縮略圖
'small': (50, 50),
'big': (200, 200),
}
運行結果:
會生成2個文件夾缸濒,
full:原圖足丢,
thumbs:縮略圖粱腻,包含2個文件夾:big、small斩跌,