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(results, items, info):
所有圖片處理完畢後(不管下載成功或失敗),會呼叫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):
函式才行