Scrapy爬圖片(二)

Scrapy第三篇: ImagesPipeline的使用

大家好呀,我來填坑了(半夜寫文也是有些醉啊,課太多沒有辦法唉。。)

上次的項目一發出,立即有盆友留言:

"看來我們開的不是一輛車"

還是您這趟比較快

(詳情請看:Scrapy爬女神圖(一)—— 這是你們要的小姐姐)

。。。。。

我,,,我還只是個純潔的寶寶好嘛。。。

不過,既然咱坑都挖了,還是得填不是?

今天就來談談,如何用Scrapy中ImagesPipeline(圖片管道),爬取可愛的小姐姐們^_^

一、基礎知識

Scrapy提供了一個item pipeline,下載某特定項目的圖片,又叫ImagesPipeline(圖片管道)

1、可以實現如下功能

  • 將所有下載的圖片轉換成通用的格式(JPG)和模式(RGB)
  • 避免重複下載已經下載過的圖
  • 生成指定縮略圖
  • 檢測圖片的寬和高,確保它們滿足最小限制

由上,為了使用ImagePipeline並獲得縮略圖,需要安裝pillow(不推薦用PIL)

2、使用ImagesPipeline工作流程

(直接截了官網的圖)

3、實現 定製圖片管道

正如工作流程所示,Pipeline將從item中獲取圖片的URLs並下載它們,

使用get_media_requests處理圖片,並返回一個Request對象,

這些請求對象將被Pipeline處理,當完成下載後,結果將發送到item_completed方法,當一個單獨項目中的所有圖片請求完成時(要麼完成下載,要麼因為某種原因下載失敗),ImagesPipeline.item_completed()方法將被調用。

結果results為一個二元組的list,每個元祖包含(success, image_info_or_error)

  • success: boolean值,success=true表示成功下載 ,反之失敗

  • image_info_or_error 是一個包含下列關鍵字的字典(如果成功為 True )或者出問題時為 Twisted Failure 。

字典包含以下鍵值對url:原始URL path:本地存儲路徑 checksum:校驗碼

失敗則包含一些出錯信息。

二、代碼修改

延續之前例子,不夠清楚噠請看上一篇文:Scrapy爬女神圖(一)—— 這是你們要的小姐姐

改動主要在settings和pipelines上

為了大家理解得更加清楚些,這回盡量多點注釋^_^

<settings部分>

# -*- coding: utf-8 -*-n# Scrapy settings for XiaoHua projectnnBOT_NAME = XiaoHuanSPIDER_MODULES = [XiaoHua.spiders]nNEWSPIDER_MODULE = XiaoHua.spidersnn#是否遵守機器人規則nROBOTSTXT_OBEY = Falsenn#一次可以requests請求的最大次數,默認16,nCONCURRENT_REQUESTS=16nn#下載延遲設置為1snDOWNLOAD_DELAY=1nn#禁用Cookies防止被bannCOOKIES_ENABLED = Falsenn#設置headersnDEFAULT_REQUEST_HEADERS = {n Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8,n Accept-Encoding:gzip, deflate, sdch,n Accept-Language:zh-CN,zh;q=0.8,n Cache-Control:max-age=0,n Connection:keep-alive,n User-Agent:Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36}nn#管道設置nITEM_PIPELINES = {XiaoHua.pipelines.XiaohuaPipeline: 1}nn#IMAGES_STORE用於設置圖片存儲路徑nIMAGES_STORE=rF:DesktopcodeinfoXiaoHua2nn#IMAGES_THUMBS用於生成大小不同的縮略圖n#以字典形式表示,鍵為文件名,值為圖片尺寸nIMAGES_THUMBS={n small: (50, 50),n big: (200, 200),}nn#以下兩個設置可以過濾尺寸小於100的圖片nIMAGES_MIN_HEIGHT=100nIMAGES_MIN_WIDTH=100nn#IMAGES_EXPIRES用於設置失效期限n#這裡是90天,避免管道重複下載最近已經下載過的nIMAGES_EXPIRES=90n

<pipelines部分>

改動最大

# -*- coding: utf-8 -*-nimport scrapynfrom scrapy.exceptions import DropItemn#需要導入ImagesPipelinenfrom scrapy.pipelines.images import ImagesPipelinenfrom XiaoHua import settingsnimport sysnreload(sys)nsys.setdefaultencoding(utf-8)nnclass XiaohuaPipeline(ImagesPipeline):nn #用get_media_requests方法進行下載控制,返回一個requests對象n #對象被Pipeline處理,下載結束後,默認直接將結果傳給item_completed方法n def get_media_requests(self, item,info):n yield scrapy.Request(item[detailURL])nn def item_completed(self,results,item,info):n #創建圖片存儲路徑n path=[x[path] for ok,x in results if ok]n #判斷圖片是否下載成功,若不成功則拋出DropItem提示n if not path:n raise DropItem(Item contains no images)n print u正在保存圖片:, item[detailURL]n print u主題, item[title]n return itemn

items部分和spiders部分相應做下精簡,為了方便查看還是貼上吧

<items部分>

# -*- coding: utf-8 -*-nn# Define here the models for your scraped itemsn# See documentation in:n# http://doc.scrapy.org/en/latest/topics/items.htmlnimport scrapynnclass XiaohuaItem(scrapy.Item):n # define the fields for your item here like:n # name = scrapy.Field()n siteURL=scrapy.Field()n pageURL=scrapy.Field()n detailURL=scrapy.Field()n title=scrapy.Field()n

<spiders部分>

# --coding:utf-8--nimport scrapynfrom XiaoHua.items import XiaohuaItemnfrom scrapy.http import Requestnimport requestsnimport renimport osnimport sysnreload(sys)nnsys.setdefaultencoding(utf-8)nnclass Myspider(scrapy.Spider):n name=XiaoHuan allowed_domains=[mmonly.cc]n def start_requests(self):n #一共有6頁n for i in range(1,7):n url=https://www.mmonly.cc/tag/xh1/+str(i)+.htmln yield Request(url,callback=self.parse_one)nn def parse_one(self,response):n #創建一個大的list存儲所有的itemn items=[]n pattern=re.compile(r<div class="title".*?<a.*?href="(.*?)">(.*?)</a></span></div>,re.S)n mains=re.findall(pattern,response.text)n for main in mains:n #創建實例,並轉化為字典n item=XiaohuaItem()n item[siteURL]=main[0]n item[title]=main[1]n items.append(item)nn for item in items:n #用meta傳入下一層n yield Request(url=item[siteURL],meta={item1:item},callback=self.parse_two)nn def parse_two(self,response):n #傳入上面的item1n item2=response.meta[item1]n source=requests.get(response.url)n html=source.text.encode(utf-8)n pattern=re.compile(r共(.*?)頁,re.S)n Num=re.search(pattern,html).group(1)n items=[]n for i in range(1,int(Num)+1):n item=XiaohuaItem()n #構造每一個圖片入口鏈接,以獲取源碼中的原圖鏈接n item[title]=item2[title]n item[pageURL]=response.url[:-5]+_+str(i)+.htmln items.append(item)n for item in items:n yield Request(url=item[pageURL],meta={item2:item},callback=self.parse_three)nn def parse_three(self,response):n item=XiaohuaItem()n item3=response.meta[item2]n #傳入上面的item2n pattern=re.compile(r<li class="pic-down h-pic-down"><a target="_blank" class="down-btn" href=(.*?)>.*?</a>,re.S)n URL=re.search(pattern,response.text).group(1)n item[detailURL]=URLn item[title]=item3[title]n yield itemn

完整版代碼下載,輕戳這裡:github地址

三、結果

結果就是下面這樣~

可以從框中看到圖片下載異常的提示(scrapy會自動跳過)

我們點開DropItem的網址,發現圖片真的不存在

由上來看,一共抓取成功2042張,失敗74張

來看文件發生了什麼變化:

點開,可以看到生成的原圖(full)和縮略圖(thumbs)文件

再點開,thumbs中分big和small,大小縮略圖,就是之前設置的字典中的鍵

點開small,可以看到圖片真的是根據URL的SHA1 hash值來自動命名的

(hash值很少會重複,所以可以實現重複判斷)

再隨便點開一個,如下,真的是縮略圖哦~

四、資料推薦

終於差不多啦,送送福利^_^

我收集了一些比較優秀的資料,大家可以做個參考~

官方文檔:Scrapy0.24—— ImagesPipeline部分

優秀博客jianshu.com/p/2528edf44

用scrapy自動爬取下載圖片

五、總結

最後連帶之前的內容一併總結下

這兩篇我們使用Scrapy抓取多級網頁及圖片

1、抓取多級網頁:用meta傳遞數據

2、Scrapy抓取圖片:scrapy框架+requests的get方式

3、Scrapy抓取圖片: scrapy框架+內置ImagesPipeline方式

兩種方式其實下載速度差不多(後面那一種可能快一些)

不過ImagesPipeline可自定義縮略圖、過濾小圖,還可將列印提示一些出錯或不存在而無法下載的圖片。 但個人感覺這個項目裡面,使用第一種,將圖片歸類(以title名)存入文件,更加清晰也易查看。

你覺得呢?

推薦閱讀:

用Python玩GTA 5—使用OpenCV讀取遊戲面面
Python and Visual C++ Build Tools
從零開始寫Python爬蟲 --- 1.3 BS4庫的解析器

TAG:Python | 爬虫 | scrapy |