天天看點

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

可以關注我的公衆号:技術趣談

scrapy自定義pipeline下載下傳圖檔/文檔