使用scrapy圖片管道下載圖片
前言
Scrapy是Python語言下一個十分流行的爬蟲框架,本文不對Scrapy本身做詳細介紹。有關Scrapy的安裝可以參考官網的安裝指南,不過本人更推薦使用Anaconda,Anaconda集成了Python和一系列常用的的Python庫,當然也包括Scrapy。安裝好Anaconda,基本上就可以直接使用Scrapy了,免去了一些麻煩的依賴的安裝。不過事情並非總是一帆風順,我們依然有可能遇到一些錯誤。本人首次使用Scrapy的時候,在操作無誤的情況下還是遇到了一個和dll檔案相關的錯誤,問題倒不大,直接把具體的錯誤資訊往google上一粘,很快就找到了解決辦法。用google!用google!用google!重要的事情說三遍。
Scrapy是一個通用的爬蟲框架,可以爬取多種形式的資料,不限於本文所講的圖片下載。關於Scrapy的工作流程、基本概念和簡單例子可以參考官網的入門教程。對於網頁上圖片的爬取來說,Scrapy專門提供了一個item pipeline,叫做圖片管道。有關圖片管道的使用,官網上在下載專案圖片部分裡也有所介紹,而本文旨在結合一個具體的例子更清晰地說明如何使用Scrapy的圖片管道爬取一個網頁上的圖片。
大概流程
使用Scrapy爬資料的流程大概包括如下4步:
- 建立一個scrapy專案。
- 定義要提取的Item。
- 編寫爬取網站的爬蟲(spider)。
- 編寫Item pipeline來處理提取到的Item。
下面,我將詳細介紹如何通過以上4步來完成對圖片的爬取。
建立Scrapy專案
本人是在Windows7環境下進行的一系列操作,使用Anaconda自帶的Scrapy,而且安裝Anaconda時也允許其將相關路徑加到了環境變數裡,對於其他情況本人並未遇到過,這裡也不做進一步的探討。先提一點題外話,開啟cmd,輸入scrapy version命令可以檢視當前使用的scrapy的版本情況,注意是version而不是常見的–version,截圖如下:
使用Scrapy建立一個專案是要從命令列敲命令完成的,可以開啟cmd,再cd到一個我們指定的路徑下,也可以直接在一個指定的空資料夾上按住shift鍵再右擊滑鼠,然後在右鍵選單裡選擇“在此處開啟命令列視窗”。無論怎樣,到了指定路徑後,鍵入命令scrapy startproject image(其中,image是我們專案的名稱),回車就可以建立專案了,如果成功的話,會出現大概如下圖所示情況:
然後到之前指定的資料夾(test)下,會發現多了一個image資料夾,這就是剛剛創建出來的。點進image資料夾,會發現一個scrapy.cfg檔案(專案配置檔案,基本上不用管)和另一個image資料夾:
再點進去,又會發現一些Python檔案和一個spiders資料夾,這些是我們需要修改來完成爬取任務的主要檔案:
定義Item
接下來就是要定義Item,也就是要爬取的目標。從上圖可以看到,items.py檔案在建立專案時已經生成好了,但是裡面並沒有實質性的內容,我們需要對它進行修改,程式碼如下:
import scrapy
class ImageItem(scrapy.Item):
image_urls = scrapy.Field()
images = scrapy.Field()
image_paths = scrapy.Field()
因為我們要爬取圖片,所以在ImageItem類裡定義了圖片的url(image_urls)、圖片的實際內容(images)以及圖片的儲存路徑(image_paths)。如果除圖片本身外還需要一些其他的資訊,比如對圖片的描述,只要是要爬取的網頁中有相關內容,這裡就可以進行定義,而實際的爬資料的程式碼要在spider類裡編寫。在Scrapy中,一個Item的所有成員變數都是用scrapy.Field()來初始化的。
編寫爬蟲
之前提到的目錄結構中,有一個spiders資料夾,這是放爬蟲檔案的地方,初始時,裡面只有一個__init__.py檔案,所以我們首先需要建立一個特定的爬蟲檔案。在命令列中,cd到這個資料夾下,使用scrapy gensipder myimage https://tianqi.moji.com/liveview/ 命令來創建出spider檔案,其中,myimage是spider的檔名,而第二個引數是一個網址,代表allowed_domains。allowed_domains是搜尋的域名範圍,也就是爬蟲的約束區域,規定爬蟲只爬取這個域名下的網頁。使用命令建立spider檔案截圖如下:
創建出的spider檔案具體內容如下:
import scrapy
class MyimageSpider(scrapy.Spider):
name = "myimage"
allowed_domains = ["https://tianqi.moji.com/liveview/"]
start_urls = (
'http://www.https://tianqi.moji.com/liveview//',
)
def parse(self, response):
pass
可以看到,類名以及其中的一些固定的成員變數都自動生成好了,類名和name變數(爬蟲的唯一標識)都是根據命令中的檔名創建出來的,而allowed_domains和start_urls是根據第二個引數建立的。start_urls就是我們要爬取的網址,它預設是和allowed_domains一樣,不過,我們這裡需要對其進行一下修改,改成一個更具體的網址,而不是一個域名約束範圍。
parse函式是進行網頁內容爬取的主要函式,起始時它沒有函式體(僅有個pass而已),針對自己的任務,我們要對這個檔案做特異的編寫,修改parse函式前,首先要import我們之前定義的item類,修改過的spider檔案程式碼如下:
# -*- coding: utf-8 -*-
import scrapy
from image.items import ImageItem
class MyimageSpider(scrapy.Spider):
name = "myimage"
allowed_domains = ["https://tianqi.moji.com/liveview/"]
start_urls = (
'https://tianqi.moji.com/liveview/china/shaanxi/qujiang-ocean-world',
)
def parse(self, response):
item = ImageItem()
item['image_urls'] = response.xpath('//img[@data-original]/@data-original').extract()
return item
注意,程式碼中我確實修改了start_urls(關於墨跡天氣時景的一個具體網址)。在parse函式中,首先建立一個item物件,然後就是解析html網頁,爬取我們想要的內容,在這裡我們想要的是網頁中圖片的地址。Scrapy使用xpath語法來解析html,可以是說這是使用scrapy做爬蟲的一個非常核心的部分,所以如果想實現自己的爬蟲,還必須瞭解xpath,推薦學習w3school的XPath教程。另外,還要對要爬取的網頁做一定的原始碼分析(網頁中點滑鼠右鍵,選檢視網頁原始碼),這樣才能針對要爬取的內容寫出真正能起作用的xpath語句。parse函式最後我們將item物件返回即可,Scrapy框架下自會有其他函式來呼叫它。圖片的儲存路徑不屬於爬蟲本身管轄的範圍,在parse函式裡不用管,而圖片的實際內容也是在爬蟲實際執行起來後,由Scrapy來負責的,這裡也不用額外處理。
編寫Item Pipeline 檔案
在建立專案時,會自動生成一個pipelines.py檔案,裡面包含一個ItemPipeline類,這個類是用來處理爬蟲爬取到的item的,比如丟掉一些錯誤的item等等。本文之前講的東西其實和本文的主題並沒有特別緊密的關係,前面的流程幾乎適用於爬任何資料。而使用Scrapy圖片管道下載圖片從這裡開始有點不一樣了。由於Scrapy為我們提供好了一個ImagesPipeline(圖片管道),所以最簡單的圖片下載方式可以不用對生成的pipelines.py檔案做任何修改,只需配置settings.py(也是建立專案時自動生成)檔案即可。settings.py檔案中需加入以下資訊:
ITEM_PIPELINES = {
'scrapy.contrib.pipeline.images.ImagesPipeline': 1
}
IMAGES_STORE = 'D:\\pachong\\images\\'
IMAGES_EXPIRES = 90
IMAGES_MIN_HEIGHT = 100
IMAGES_MIN_WIDTH = 100
其中,ITEM_PIPELINES = { ‘scrapy.contrib.pipeline.images.ImagesPipeline’: 1}指定了使用Scrapy提供的ImagesPipeline來做ItemPipeline。IMAGES_EXPIRES指定的是圖片的過期時間。IMAGES_STORE 指定了圖片的儲存路徑,IMAGES_MIN_HEIGHT和IMAGES_MIN_HEIGHT分別指定圖片的最小高度和最小寬度,起到一個過濾的作用。settings.py還有一個地方要改,那就是把ROBOTSTXT_OBEY由True改成False。否則,一些防爬蟲爬資料的頁面可能會拒絕請求,本人遇到的情況如下圖所示:
Scrapy預設遵守robot協議,也就是ROBOTSTXT_OBEY的初值為True。但是遇到防爬取頁面,就會碰壁。
最後就是實際執行爬蟲爬資料了,在命令列中,cd到我們之前建立的專案路徑下,鍵入scrapy crawl myimage命令,回車即可開始工作。myimage就是爬蟲檔案的檔名,也是檔案中name變數對應的值。執行結果如下:
爬蟲工作完之後,我們會在settings.py指定的儲存資料夾下,看到剛下載到的圖片:
總結
到此,使用Scrapy提供的圖片管道下載圖片的整個流程就介紹完了。如果還想對這些圖片做一些額外的處理,比如規定它們的檔名,那就需要實現定製圖片管道了,本文就不對這部分做介紹了,可以參考官網下載專案圖片或者其他部落格,比如這篇scrapy 下載圖片 ImagesPipeline。記得要在settings.py檔案中將ITEM_PIPELINES設為自己的ItemPipeline。