1. 程式人生 > >scrapy自定義pipeline下載圖片/文件

scrapy自定義pipeline下載圖片/文件

自定義圖片/文件下載pipeline,自定義一個自己需要的路徑來儲存下載的圖片/文件

自定義pipeline可以基於scrapy自帶的ImagesPipeline的基礎上完成。
可以重寫ImagesPipeline中的三個法:get_media_requests(),file_path(),item_completed()

首先是在spider.py(自己的爬蟲檔案)檔案中獲取自己想要新增路徑的名字,name為自己新增的檔案路徑

item = ZhanzhangsucaispiderItem()
item["name"]=response.meta["name"]#meta是以字典是的形式傳給response的.
item["img_url"] = [src]
yield item

然後將item返回出去,再在items.py檔案中宣告一下name, img_path是pipeline.py檔案中需要的。後邊會介紹。

class ZhanzhangsucaispiderItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = scrapy.Field()
    img_url = scrapy.Field()
    img_path = scrapy.Field()

接下來修改pipeline.py檔案

import scrapy
#匯入系統檔案images.py裡的ImagesPipeline類.
from scrapy.pipelines.images import ImagesPipeline
#DropItem是用來刪除下載圖片失敗的item的
from scrapy.exceptions import DropItem

#自定義一個類,繼承於ImagesPipeline,對ImagesPipeline進行重寫,以實現自己需要的功能
class CustomImageDownloadPipleline(ImagesPipeline):
    #上邊說過這個三函式都是ImagesPipeline類裡的函式.
    def get_media_requests(self, item, info):
        #img_url是下載圖片的地址,存放在item(具有類似字典的功能)中,
        for image_url in item["img_url"]:
            #將下載好的圖片返回給file_path函式,圖片的儲存需要自己給他新增一個路徑,並且要給圖片起一個名字,而這些引數都在item中,file_path沒有接收item的引數,所以需要將item以字典的形式傳給meta,跟隨下載的圖片一塊傳給file_path函式.
            yield scrapy.Request(url=image_url,meta={"item":item})

    #response=None,是因為file_path函式是用來儲存圖片的,而不是解析response的資料;官方文件中的file_path作用是將圖片的下載網址給加密,並且返回圖片下載的路徑
    def file_path(self, request, response=None, info=None):
        #將item取出來
        item = request.meta["item"]
        #再從item中取出分類名稱,這個name就是我們想自定義圖片路徑的檔名稱,(如果不自定義file_path函式的話,預設會將圖片下載到full檔案裡)
        name = item["name"]
        #再從item中取出img_url,分隔出來圖片的名稱.圖片的網址一般最後一個'/'後都是數字,此處用它作圖片的名字
        img_url_name = item["img_url"][0].split("/")[-1]
        return "%s/%s"%(name,img_url_name)


    #專案管道里面的每一個item最終都會經過item_completd,也就是意味著有多少個item,這個item_completed函式就會被呼叫多少次。(不管下載成功,還是失敗都會被呼叫),如果不重寫該方法,item預設都會返回出去。item_completed裡面的return出去的item是經過整個專案管道處理完成之後的最終的一個item。
    def item_completed(self, results, item, info):
        #在這通過debug可以看到results裡資料,分下載圖片成功和下載失敗兩種情況.
        #如果下載成功results的結果:[(True, {'url': 'http://pics.sc.chinaz.com/Files/pic/icons128/7152/f1.png', 'path': '人物頭像圖示下載/f1.png', 'checksum': 'eb7f47737a062a1525457e451c41cc99'})]
        #True:代表圖片下載成功
        #url:圖片的地址
        #path:圖片的儲存路徑
        #checksum:圖片內容的 MD5 hash加密字串
        #如果下載失敗results的結果:[(False, <twisted.python.failure.Failure scrapy.pipelines.files.FileException: 'NoneType' object has no attribute 'split'>)]
        #False:代表下載失敗
        #error:下載失敗的原因
        
        #將圖片的下載路徑取出來(資料夾名/圖片名)
        image_path = results[0][1].get("path")
        if not image_path:
            # 如果圖片下載失敗,則取不到image_path,那就說明對應的item是有問題的,就刪除這個item。
            raise DropItem("圖片下載失敗,刪除對應的item,不讓該item返回出去。")
        #如果能取到img_path,說明該item是一個正常的item,可以返回出去。這個時候可以給item新增一個img_path的值,最後給這個item返回出去,這個item就是經過整個管道處理完成之後的最終的一個item。
        item["img_path"]= image_path
        print("item_completed函式被呼叫了!")
        print(item)
        # 為什麼要renturn這個item,因為後面還有其他的管道(pipeline)會處理這個item,所以需要給它return出去。
        return item

    

最後需要修改settings.py檔案裡的內容,第67行

ITEM_PIPELINES = {
    "ZhanZhangSuCaiSpider.pipelines.CustomImageDownloadPipleline":300,
}
IMAGES_STORE = "C:/Users/Administrator/Desktop/img"

例項可以參考連結https://blog.csdn.net/cp_123321/article/details/84675034