Scrapy學(xué)習(xí)篇(九)之文件與圖片下載

Media Pipeline

Scrapy為下載item中包含的文件(比如在爬取到產(chǎn)品時(shí)资柔,同時(shí)也想保存對(duì)應(yīng)的圖片)提供了一個(gè)可重用的 item pipelines . 這些pipeline有些共同的方法和結(jié)構(gòu)(稱(chēng)之為media pipeline)狼纬。我們可以使用FilesPipeline和Images Pipeline來(lái)保存文件和圖片宫峦,他們有以下的一些特點(diǎn):

  • Files Pipeline

    • 避免重新下載最近已經(jīng)下載過(guò)的數(shù)據(jù)
    • 指定存儲(chǔ)路徑

    FilesPipeline的典型工作流程如下:

    1. 在一個(gè)爬蟲(chóng)里,你抓取一個(gè)項(xiàng)目砚殿,把其中圖片的URL放入 file_urls 組內(nèi)戏售。
    2. 項(xiàng)目從爬蟲(chóng)內(nèi)返回,進(jìn)入項(xiàng)目管道贷帮。
    3. 當(dāng)項(xiàng)目進(jìn)入 FilesPipeline,file_urls 組內(nèi)的URLs將被Scrapy的調(diào)度器和下載器(這意味著調(diào)度器和下載器的中間件可以復(fù)用)安排下載定硝,當(dāng)優(yōu)先級(jí)更高皿桑,會(huì)在其他頁(yè)面被抓取前處理毫目。項(xiàng)目會(huì)在這個(gè)特定的管道階段保持“l(fā)ocker”的狀態(tài)蔬啡,直到完成文件的下載(或者由于某些原因未完成下載)。
    4. 當(dāng)文件下載完后镀虐,另一個(gè)字段(files)將被更新到結(jié)構(gòu)中箱蟆。這個(gè)組將包含一個(gè)字典列表,其中包括下載文件的信息刮便,比如下載路徑空猜、源抓取地址(從 file_urls 組獲得)和圖片的校驗(yàn)碼(checksum)。 files 列表中的文件順序?qū)⒑驮?file_urls 組保持一致恨旱。如果某個(gè)圖片下載失敗辈毯,將會(huì)記錄下錯(cuò)誤信息,圖片也不會(huì)出現(xiàn)在 files 組中搜贤。
  • Images Pipeline

    • 避免重新下載最近已經(jīng)下載過(guò)的數(shù)據(jù)
    • 指定存儲(chǔ)路徑
    • 將所有下載的圖片轉(zhuǎn)換成通用的格式(JPG)和模式(RGB)
    • 縮略圖生成
    • 檢測(cè)圖像的寬/高谆沃,確保它們滿(mǎn)足最小限制

    和FilesPipeline類(lèi)似,除了默認(rèn)的字段名不同仪芒,image_urls保存圖片URL地址唁影,images保存下載后的圖片信息耕陷。當(dāng)然,它還提供了一些拓展功能据沈,比如圖片的縮略圖哟沫,過(guò)濾圖片的尺寸。
    注意:你需要安裝Pillow 庫(kù)來(lái)實(shí)現(xiàn)以上的拓展功能锌介。

啟用Media Pipeline

要想使用media pipeline嗜诀,你需要在設(shè)置添加一些必要的信息。

# 同時(shí)啟用圖片和文件管道
ITEM_PIPELINES = {
                  'scrapy.pipelines.images.ImagesPipeline': 1,
                  'scrapy.pipelines.files.FilesPipeline': 2,
                 }
FILES_STORE = 'D:'  # 文件存儲(chǔ)路徑
IMAGES_STORE = 'D' # 圖片存儲(chǔ)路徑

# 避免下載最近90天已經(jīng)下載過(guò)的文件內(nèi)容
FILES_EXPIRES = 90
# 避免下載最近90天已經(jīng)下載過(guò)的圖像內(nèi)容
IMAGES_EXPIRES = 30

# 設(shè)置圖片縮略圖
IMAGES_THUMBS = {
    'small': (50, 50),
    'big': (250, 250),
}
# 圖片過(guò)濾器孔祸,最小高度和寬度裹虫,低于此尺寸不下載
IMAGES_MIN_HEIGHT = 110
IMAGES_MIN_WIDTH = 110

你可能會(huì)好奇文件的命名,在當(dāng)你啟用media pipeline以后融击,
它的默認(rèn)命名方式是這樣的筑公,文件以它們URL的 SHA1 hash 作為文件名。
例如尊浪,
對(duì)下面的圖片URL:http://www.example.com/image.jpg,
其SHA1 hash 值為:3afec3b4765f8f0a07b78f98c07b83f013567a0a
將被下載并存為下面的文件:<IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg
其中匣屡,<IMAGES_STORE> 是定義在 IMAGES_STORE 設(shè)置里的文件夾,我們?cè)O(shè)置的是D盤(pán)拇涤,full 是用來(lái)區(qū)分圖片和縮略圖(如果使用的話(huà))的一個(gè)子文件夾捣作,這個(gè)文件夾scrapy會(huì)自動(dòng)生成。

擴(kuò)展Media Pipeline

下面我們以ImagesPipeline為例來(lái)自定義ImagesPipeline鹅士,需要重寫(xiě)以下兩個(gè)方法:

  • get_media_requests(item, info)
    在工作流程中可以看到券躁,管道會(huì)得到圖片的URL并從項(xiàng)目中下載。為了這么做掉盅,你需要重寫(xiě) get_media_requests() 方法也拜,并對(duì)各個(gè)圖片URL返回一個(gè)Request:

    def get_media_requests(self, item, info):
        for image_url in item['image_urls']:
            yield scrapy.Request(image_url)
    

    這些請(qǐng)求將被管道處理,當(dāng)它們完成下載后趾痘,結(jié)果將以2元素的元組列表形式傳送到 item_completed() 方法: 每個(gè)元組包含 (success, file_info_or_error):

    • success 是一個(gè)布爾值慢哈,當(dāng)圖片成功下載時(shí)為 True ,因?yàn)槟硞€(gè)原因下載失敗為False

    • file_info_or_error 是一個(gè)包含下列關(guān)鍵字的字典(如果成功為 True )或者出問(wèn)題時(shí)為 Twisted Failure 永票。
      url - 文件下載的url卵贱。這是從 get_media_requests() 方法返回請(qǐng)求的url。
      path - 圖片存儲(chǔ)的路徑(類(lèi)似 IMAGES_STORE)
      checksum - 圖片內(nèi)容的 MD5 hash
      item_completed() 接收的元組列表需要保證與 get_media_requests() 方法返回請(qǐng)求的順序相一致侣集。下面是 results 參數(shù)的一個(gè)典型值:

      [(True,
        {'checksum': '2b00042f7481c7b056c4b410d28f33cf',
         'path': 'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg',
         'url': 'http://www.example.com/files/product1.jpg'}),
       (False,
        Failure(...))]
      

      該方法 必須返回每一個(gè)圖片的URL键俱。

  • item_completed(results, items, info)
    當(dāng)一個(gè)單獨(dú)項(xiàng)目中的所有圖片請(qǐng)求完成時(shí),例如,item里面一共有10個(gè)URL世分,那么當(dāng)這10個(gè)URL全部下載完成以后编振,ImagesPipeline.item_completed() 方法將被調(diào)用。默認(rèn)情況下罚攀, item_completed() 方法返回item党觅。

使用ImagesPipeline下載圖片

下面我們用上面學(xué)習(xí)到的知識(shí)來(lái)下載一些圖片雌澄。
我們以http://jandan.net/ooxx為例,把頁(yè)面上的圖片下載下來(lái)杯瞻,并產(chǎn)生縮略圖
我們新建一個(gè)項(xiàng)目镐牺,名為jiandan,各個(gè)文件內(nèi)容如下魁莉。

  • item.py
import scrapy

class JiandanItem(scrapy.Item):
    image_urls = scrapy.Field()#圖片的鏈接
    images = scrapy.Field()
  • jiandan_spider.py
import scrapy
from jiandan.items import JiandanItem

class jiandanSpider(scrapy.Spider):
    name = 'jiandan'
    start_urls = ["http://jandan.net/ooxx"]

    def parse(self, response):

        item = JiandanItem()
        item['image_urls'] = response.xpath('//img//@src').extract() #提取圖片鏈接
        yield item
  • settings.py
BOT_NAME = 'jiandan'

SPIDER_MODULES = ['jiandan.spiders']
NEWSPIDER_MODULE = 'jiandan.spiders'

DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
    'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
}

ITEM_PIPELINES = {
   'jiandan.pipelines.JiandanPipeline':1,
}
IMAGES_STORE='H:\\jiandan'
IMAGES_THUMBS = {
    'small': (50, 50),
    'big': (200, 200),
}
  • pipelinse.py
import scrapy
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline   #內(nèi)置的圖片管道

class JiandanPipeline(ImagesPipeline):#繼承ImagesPipeline這個(gè)類(lèi)

    def get_media_requests(self, item, info):
        for image_url in item['image_urls']:
            image_url = "http://" + image_url
            yield scrapy.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")
        return item

運(yùn)行這個(gè)spider睬涧,你會(huì)發(fā)現(xiàn),圖片已經(jīng)下載好了旗唁,如下圖所示畦浓。




圖片內(nèi)容你可以自己慢慢看。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末检疫,一起剝皮案震驚了整個(gè)濱河市讶请,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夺溢,老刑警劉巖风响,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件双泪,死亡現(xiàn)場(chǎng)離奇詭異朵诫,居然都是意外死亡废累,警方通過(guò)查閱死者的電腦和手機(jī)邑滨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)面哥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事怎爵。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵故痊,是天一觀的道長(zhǎng)慨菱。 經(jīng)常有香客問(wèn)我,道長(zhǎng)协饲,這世上最難降的妖魔是什么把夸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任嘹狞,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好袄简,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布秃症。 她就那樣靜靜地躺著,像睡著了一般吕粹。 火紅的嫁衣襯著肌膚如雪种柑。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天匹耕,我揣著相機(jī)與錄音聚请,去河邊找鬼。 笑死稳其,一個(gè)胖子當(dāng)著我的面吹牛驶赏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播欢际,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼母市,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了损趋?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浑槽,沒(méi)想到半個(gè)月后蒋失,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桐玻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年篙挽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镊靴。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铣卡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出偏竟,到底是詐尸還是另有隱情煮落,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布踊谋,位于F島的核電站蝉仇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏殖蚕。R本人自食惡果不足惜轿衔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望睦疫。 院中可真熱鬧害驹,春花似錦、人聲如沸蛤育。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)缨伊。三九已至摘刑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刻坊,已是汗流浹背枷恕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谭胚,地道東北人徐块。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像灾而,于是被迫代替她去往敵國(guó)和親胡控。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容