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部分
優秀博客: http://www.jianshu.com/p/2528edf4485c
用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庫的解析器