Python爬蟲5.9 — scrapy框架下載文件和圖片
綜述
本系列文檔用於對Python爬蟲技術的學習進行簡單的教程講解,鞏固自己技術知識的同時,萬一一不小心又正好對你有用那就更好了。
Python 版本是3.7.4
本篇文章主要pipeline模塊下載文件和圖片的使用。
下載文件和圖片
Scrapy爲下載item中包含的文件(比如再爬取到產品時,同時也想保存到對應圖片)提供了一個可重用的item pipeline
。這些pipeline
有些共同的方法和結構(我們稱之爲media Pipeline
),一般來說我們會使用到File Pipeline
和Images Pipeline
。
使用Scrapy框架內置方法的好處
我們爲什麼要選擇用Scrapy
內置的下載文件的防範:
- 避免重複下載最近已經下載過的數據。
- 可以方便的指定文件存儲的路徑。
- 可以將下載的圖片轉存成通用的格式,比如png或jpg
- 可以方便的生成縮略圖。
- 可以方便的檢測圖片的寬和高,確保他們滿足最小限制。
- 異步下載,效率非常高。
下載文件的File Pipeline
當使用File Pipeline
下載文件的時候,按照以下步驟來完成:
- 定義好一個
Item
,然後再這個Item
中定義兩個屬性,分別爲file_urls
以及files
。file_urls
是用來存儲需要下載的文件的url鏈接,需要給一個列表。 - 當文件下載完成後,會把文件下載相關的信息存儲到
item
的files
屬性中。比如下載路徑、下載的url和文件的校驗碼等。 - 在配置文件
setting.py
中配置FILES_STORE
,這個配置時用來設置文件下載下來的路徑。 - 啓動
pipeline
:在ITEM_PIPELINES
中設置scrapy.pipelines.files.FilesPipeline:1
。
下載圖片的Images Pipeline
當使用Images Pipeline
下載文件的時候,按照以下步驟來完成:
- 定義好一個
Item
,然後再這個Item
中定義兩個屬性,分別爲image_urls
以及images
。image_urls
是用來存儲需要下載的圖片的url鏈接,需要給一個列表。 - 當文件下載完成後,會把圖片下載相關的信息存儲到
item
的images
屬性中。比如下載路徑、下載的url和圖片的校驗碼等。 - 在配置文件
setting.py
中配置IMAGES_STORE
,這個配置時用來設置文件下載下來的路徑。 - 啓動
pipeline
:在ITEM_PIPELINES
中設置scrapy.pipelines.images.ImagesPipeline:1
。
實例說明
我們就以爬取汽車之家中的圖片爲例。
傳統下載方式
傳統的下載方式在這裏就簡單說下步驟:
- 使用scrapy命令創建項目;
- 使用命令創建爬蟲;
- 更改
setting.py
文件配置信息; - 編寫
items.py
代碼; - 編寫
spider
模塊下代碼(爬取網頁中需要下載的圖片鏈接); - 編寫
pipelines.py
代碼(進行數據處理,圖片的保存等)。
pipelines.py
代碼如下:
import os
import urllib.request
class BmwPipeline(object):
def __init__(self):
# 創建文件保存文件夾
self.image_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images')
if not os.path.exists(self.image_path):
os.mkdir(self.image_path)
def process_item(self, item, spider):
category = item['category']
img_urls = item['img_urls']
# 創建圖片類別文件夾
category_path = os.path.join(self.image_path, category)
if not os.path.exists(category_path):
os.mkdir(category_path)
# 根據圖片url進行下載保存圖片
for url in img_urls:
img_name = url.split('_')[-1]
urllib.request.urlretrieve(url=url, filename=os.path.join(category_path, img_name))
print(img_name)
return item
通過上述代碼我們就可以將爬取的圖片url進行處理保存圖片到本地。但是這種處理方式一個很大的缺點就是圖片只能一個一個下載不能進行異步下載。下面我們使用Scrapy
框架中自帶的圖片下載進行下載圖片。
使用Scrapy
框架自帶ImagesPipeline
進行下載圖片
按照上述的步驟進行編寫相應的代碼:
- 定義好一個
Item
,然後再這個Item
中定義兩個屬性,分別爲image_urls
以及images
。編寫items.py
代碼如下:import scrapy class BmwItem(scrapy.Item): category = scrapy.Field() image_urls = scrapy.Field() images = scrapy.Field()
- 在配置文件
setting.py
中配置IMAGES_STORE
。增加代碼如下:# 圖片下載路徑,供image pipeline使用 IMAGES_STORE = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images')
- 啓動
pipeline
:在ITEM_PIPELINES
中設置scrapy.pipelines.images.ImagesPipeline:1
。修改代碼如下:ITEM_PIPELINES = { # 'bmw.pipelines.BmwPipeline': 300, 'scrapy.pipelines.images.ImagesPipeline': 1 }
- 編寫
spider
模塊代碼如下:import scrapy from bmw.items import BmwItem class Bmw5Spider(scrapy.Spider): name = 'bmw5' allowed_domains = ['car.autohome.com.cn'] start_urls = ['https://car.autohome.com.cn/pic/series/65.html'] def parse(self, response): uiboxs = response.xpath('//div[@class="uibox"]')[1:] for uibox in uiboxs: category = uibox.xpath('.//div[@class="uibox-title"]/a/text()').get() img_urls_tmp = uibox.xpath('.//ul/li/a/img/@src').getall() img_urls = list(map(lambda url:response.urljoin(url),img_urls_tmp)) item = BmwItem(category=category,image_urls=img_urls) yield item
運行代碼你會發現其能很快的將圖片下載完成。下載完成後你會在你定義的圖片保存文件夾images
下多了一個full
文件夾,這個裏面就是所下載下來的所有圖片。有的想問如果我還想要根據分類繼續保存圖片需要怎麼辦呢?這就需要我們去重寫ImagesPipeline
類中的一些方法了。通過讀ImagesPipeline
類的代碼我們可以知道,類中有兩個方法分別是get_media_requests
和file_path
。
get_media_requests
: 這個方法是在發送下載請求之前調用,其實這個方法本身就是去發送下載請求的。file_path
: 這個方式是在圖片將要被存儲時候調用,來獲取這個圖片的存儲路徑。
優化方案如下:
- 在
pipelines.py
中重寫聲明定義一個類,繼承ImagesPipeline
; - 在此子類中重新這兩個方法代碼如下:
import os import urllib.request from scrapy.pipelines.images import ImagesPipeline from bmw import settings class BmwImagesPipeline(ImagesPipeline): # 重寫get_media_requests方法 def get_media_requests(self, item, info): # 這個方法是在發送下載請求之前調用 # 其實這個方法本身就是去發送下載請求的 request_objs = super(BmwImagesPipeline, self).get_media_requests(item, info) # 將item數據加入到請求中 for requests_obj in request_objs: requests_obj.item = item return request_objs # 重寫file_path方法 def file_path(self, request, response=None, info=None): # 這個方式是在圖片將要被存儲時候調用,來獲取這個圖片的存儲路徑 # 獲取父類返回的保存地址 path = super(BmwImagesPipeline, self).file_path(request, response, info) category = request.item.get('category') images_store = settings.IMAGES_STORE # 創建圖片分類文件夾 category_path = os.path.join(images_store, category) if not os.path.exists(category_path): os.mkdir(category_path) # 重新返回新的圖片保存路徑 image_name = path.replace('full/', '') image_path = os.path.join(category_path, image_name) return image_path
- 重新修改
setting.py
中的ITEM_PIPELINES
配置如下:ITEM_PIPELINES = { # 'bmw.pipelines.BmwPipeline': 300, # 'scrapy.pipelines.images.ImagesPipeline': 1 'bmw.pipelines.BmwImagesPipeline': 300, }
之後運行代碼即可。
其他博文鏈接
- Python爬蟲1.1 — urllib基礎用法教程
- Python爬蟲1.2 — urllib高級用法教程
- Python爬蟲1.3 — requests基礎用法教程
- Python爬蟲1.4 — requests高級用法教程
- Python爬蟲2.1 — BeautifulSoup用法教程
- Python爬蟲2.2 — xpath用法教程
- Python爬蟲3.1 — json用法教程
- Python爬蟲3.2 — csv用法教程
- Python爬蟲3.3 — txt用法教程
- Python爬蟲4.1 — threading(多線程)用法教程
- Python爬蟲4.2 — ajax(動態網頁數據抓取)用法教程
- Python爬蟲4.3 — selenium基礎用法教程
- Python爬蟲4.4 — selenium高級用法教程
- Python爬蟲4.5 — tesseract(圖片驗證碼識別)用法教程
- Python爬蟲5.1 — scrapy框架簡單入門
- Python爬蟲5.2 — scrapy框架pipeline模塊的使用
- Python爬蟲5.3 — scrapy框架spider[Request和Response]模塊的使用
- Python爬蟲5.4 — scrapy框架items模塊的使用
- Python爬蟲5.5 — scrapy框架logging模塊的使用
- Python爬蟲5.6 — scrapy框架setting模塊的使用
- Python爬蟲5.7 — scrapy框架Shell命令的使用
- Python爬蟲5.8 — scrapy框架CrawlSpider模塊的使用