1. 程式人生 > >python scrapy 使用ImagePipeline下載圖片

python scrapy 使用ImagePipeline下載圖片

 

在scrapy中,為了爬取圖片,可以將要爬取的圖片的url放在image_urls欄位中,在item從spider返回時,ImagePipeline會自動高優先順序抓取這些url,於此同時,item會被鎖定直到圖片抓取完畢才被解鎖。圖片下載成功結束後,圖片下載路徑、url等資訊會被填充到images欄位中。

要想圖片被成功抓取,需要做以下操作:

(1) 在items.py中新增image_urls和images欄位,程式碼如下:

image_urls = Field()

images = Field()

(2) Enable ImagePipeline,在segttings.py中新增以下程式碼:

ITEM_PIPELINES = [’scrapy.contrib.pipeline.images.ImagesPipeline’]

IMAGES_STORE = ’/path/to/valid/dir’ #設定圖片下載路徑

(3) 圖片儲存

圖片會根據原始url計算SHA1 hash值後進行儲存;

如url:http://www.example.com/image.jpg

SHA1 雜湊值為:3afec3b4765f8f0a07b78f98c07b83f013567a0a

被儲存為:<IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg

(4) 避免重複抓取

近期抓取過的圖片不會再重抓,可以在settings.py中設定多少天內抓過的不被重抓。

IMAGES_EXPIRES = 90 #90天內抓取的都不會被重抓

(5) 圖片壓縮

IMAGES_THUMBS = {

’small’: (50, 50),

’big’: (270, 270),

}

壓縮後存放在:<IMAGES_STORE>/thumbs/<size_name>/<image_id>.jpg

(6) 圖片過濾

可以設定過濾下圖片,設定方法如下:

IMAGES_MIN_HEIGHT = 110

IMAGES_MIN_WIDTH = 110

(7) 自定義ImagePipeline

可過載的函式:

get_media_requests(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 Request(image_url)

圖片下載完畢後,處理結果會以二元組的方式返回給item_completed()函式。這個二元組定義如下:

(success, image_info_or_failure)

其中,第一個元素表示圖片是否下載成功;第二個元素是一個字典,含義如下:

-url:圖片url

-path:圖片儲存地址,跟IMAGE_STORE相關

-checksum:圖片內容hash

get_media_requests函式返回示例如下:

[(True,

{’checksum’: ’2b00042f7481c7b056c4b410d28f33cf’,

’path’: ’full/7d97e98f8af710c7e7fe703abc8f639e0ee507c4.jpg’,

’url’: ’http://www.example.com/images/product1.jpg’}),

(True,

{’checksum’: ’b9628c4ab9b595f72f280b90c4fd093d’,

’path’: ’full/1ca5879492b8fd606df1964ea3c1e2f4520f076f.jpg’,

’url’: ’http://www.example.com/images/product2.jpg’}),

(False,

Failure(...))]

item_completed(resultsitemsinfo):

所有圖片處理完畢後(不管下載成功或失敗),會呼叫item_completed進行處理;示例程式如下:(預設情況下,item_completed會返回全部items

from scrapy.exceptions import DropItem

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

(8) 自定義ImagePipeline示例:

from scrapy.contrib.pipeline.images import ImagesPipeline

from scrapy.exceptions import DropItem

from scrapy.http import Request

class MyImagesPipeline(ImagesPipeline):

def get_media_requests(self, item, info):

for image_url in item[’image_urls’]:

yield Request(image_url)

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

 

通過在setting.py檔案中通過給IMAGES_STORE賦值,就可以指定圖片的儲存路徑。
並且預設情況下,檔名是通過對url使用SHA1 hash得來的。
現在我想以原來的圖片名進行儲存.

檢視下ImagePipeline的原始碼,發現可以重寫file_path函式以修改圖片名稱,例如:

def file_path(self, request, response=None, info=None):
    image_guid = request.url.split('/')[-1]
    file_name= image_guid.split('.')[0]+'.jpg'
    return 'full/%s' % (file_name)

這樣儲存的圖片就是原圖片名,但是thumbs裡面的還是雜湊名,這個可能要修改

def thumb_path(self, request, thumb_id, response=None, info=None):

函式才行