1. 程式人生 > >使用Scrapy框架對圖片按文件夾分類下載

使用Scrapy框架對圖片按文件夾分類下載

下載安裝 cal 底部 我們 shell 爬取 c++ spa pytho

應室友需求,這裏我打算使用python的scrapy框架去下載“優美圖庫”上的美圖,話不多說這就開始行動。

一、工欲善其事,必先利其器

第一步,配置scrapy爬蟲環境,先將pip換到國內阿裏雲的源。在用戶目錄下新建pip/pip.ini:

1 [global]
2 index-url = https://mirrors.aliyun.com/pypi/simple
3 trusted-host = mirrors.aliyun.com

我這裏是Windows環境,要手動下載安裝Twisted包,否則會提示需要VC++14.0:

技術分享圖片

下載地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted

找到和自己python對應版本的包,我這裏是python3.7-32(學校機房都是32位系統...),所以應選擇:

技術分享圖片

然後安裝scrapy:$ pip install scrapy

此外,由於我們是爬取圖片,需要pillow包,使用scrapy shell則要安裝win32api,於是這裏一並裝上:$ pip install pillow pypiwin32

***非常重要***

Python采用縮進來控制代碼塊,請不要混用tap和空格,否則會報語法錯誤。我這裏使用notepad++編輯器,可在設置>首選項>語言>制表符設置替換為空格:

技術分享圖片

準備工作完畢以後,現在來開始我們的爬蟲之旅。

二、Scrapy基礎

首先新建一個項目:$ scrapy startproject girls

其中girls為項目名稱,可以看到將會創建一個girls文件夾,目錄結構大致如下:

技術分享圖片

這些文件分別是:

scrapy.cfg:項目的配置文件

girls/items.py:項目的目標文件

girls/pipelines.py:項目的管道文件

girls/settings.py:項目的設置文件

girls/spiders/:存儲爬蟲代碼目錄

然後需要明確目標:我們要抓取https://www.umei.cc/tags/meinv.htm網站裏的所有美圖。打開girls目錄下的items.py文件,編輯GirlsItem類:

1 class GirlsItem(scrapy.Item):
2     # define the fields for your item here like:
3     name = scrapy.Field() #圖片名
4     image_url = scrapy.Field() #圖片鏈接
5     pass

然後進入到girls目錄下輸入如下命令創建一個girl爬蟲:

$ scrapy genspider girl ‘umei.cc‘

會看到spiders目錄下新增了girl.py文件,主要是編寫這個爬蟲文件。首先將起始網頁修改為:

1 start_urls = [http://www.umei.cc/tags/meinv.htm]

分析網頁的程序在parse方法裏編寫。

三、下載圖片

接下來分析一下目標網頁,用谷歌瀏覽器打開網頁,也在控制臺用scrapy shell打開網址:

$ scrapy shell http://www.umei.cc/tags/meinv.htm

在瀏覽器端使用右鍵檢查圖片元素可以看到每一頁都是一個TypeList列表,找到TypeList下的超鏈接:

技術分享圖片

>>> list = response.xpath(‘//div[@class="TypeList"]/ul/li/a/@href‘).extract()

可以輸出list看看:

技術分享圖片

隨便進入一個超鏈接:

$ scapy shell https://www.umei.cc/meinvtupian/meinvxiezhen/194087.htm

會看到下面有關於這個主題的一系列圖片,我們的目標是把這些圖片按標題文件夾分類存放,圖片名稱則按順序編號。

於是我們先找到圖片:

>>> img = response.xpath(‘//div[@class="ImageBody"]/p/a/img‘)

可以看到img的alt屬性就是我們要的文件夾名,而src就是要下載的圖片,可以把圖片地址顯示出來看看:

技術分享圖片

找到當前圖片的索引,按順序編號存放:

>>> index = response.xpath(‘//li[@class="thisclass"]/a/text()‘).extract_first()

不排除圖片有png或其他格式的,為了寫出更健壯的程序,所以應該取出url最後的文件擴展名:

# 新建一個圖片對象
item = GirlsItem()
item[image_url] = img.xpath(@src).extract_first()
image_type = item[image_url].split(.)[-1] # 獲取圖片擴展名
item[name] = img.xpath(@alt).extract_first() + / + index + . + image_type
yield item

接下來便是獲取下一張圖片,找到底部分頁索引:

技術分享圖片

提取出下一頁的鏈接:

>>> next_page = response.xpath(‘//div[@class="NewPages"]/ul/li/a/@href‘)[-1].extract()

需要註意這是一個相對地址,我們要的是絕對地址,還好scrapy已經幫我們解決了問題:

>>> response.urljoin(next_page)

最前面的首頁下面也有一個分頁索引,也就是TypeList的分頁索引,當然也不能放過:

技術分享圖片

需要回到上一頁的地址,然後:

>>> next_url = response.xpath(‘//div[@class="NewPages"]/ul/li‘)[-2].xpath(‘a/@href‘).extract_first()

取出“下一頁”的鏈接。

接下來只需要按照上面的流程遞歸的爬取每一張圖片即可,完整的girl.py文件內容如下:

 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 from girls.items import GirlsItem
 4 
 5 class GirlSpider(scrapy.Spider):
 6     name = girl
 7     allowed_domains = [umei.cc]
 8     start_urls = [http://www.umei.cc/tags/meinv.htm]
 9 
10     def parse(self, response):
11         list = response.xpath(//div[@class="TypeList"]/ul/li/a/@href).extract()
12         for url in list:
13             yield scrapy.Request(response.urljoin(url), callback = self.myParse)
14         
15         next_url = response.xpath(//div[@class="NewPages"]/ul/li)[-2].xpath(a/@href).extract_first()
16         if next_url:
17             yield scrapy.Request(response.urljoin(next_url), callback = self.parse)
18     
19     # 下載每一個主題內的圖片
20     def myParse(self, response):
21         img = response.xpath(//div[@class="ImageBody"]/p/a/img)
22         index = response.xpath(//li[@class="thisclass"]/a/text()).extract_first()
23         
24         item = GirlsItem()
25         item[image_url] = img.xpath(@src).extract_first()
26         image_type = item[image_url].split(.)[-1]
27         item[name] = img.xpath(@alt).extract_first() + / + index + . + image_type
28         yield item
29         
30         next_page = response.xpath(//div[@class="NewPages"]/ul/li/a/@href)[-1].extract()
31         if next_page != #:
32             yield scrapy.Request(response.urljoin(next_page), callback = self.myParse)

重要的是管道文件(pipelines.py)的編寫,我們要繼承scrapy的ImagesPipeline,先重載get_media_requests方法將文件名封裝到元數據(meta)裏,然後重載路徑函數file_path獲取文件名,pipelines.py修改如下:

1 from scrapy.pipelines.images import ImagesPipeline
2 from scrapy import Request
3 
4 class GirlsPipeline(ImagesPipeline):
5     def get_media_requests(self, item, info):
6         yield Request(item[image_url], meta = {name: item[name]})
7     
8     def file_path(self, request, response = None, info = None):
9         return request.meta[name]

然後在配置文件(settings.py)裏啟用我們的管道文件:

技術分享圖片

由於只有一個管道,後面的優先級可任意,這裏默認的是300。

最後,運行爬蟲:$ scrapy crawl girl。無奈學校機房電腦只能用https協議,拿室友電腦跑了一下,見下圖:

技術分享圖片

源碼下載:https://files.cnblogs.com/files/viewts/girls.7z

使用Scrapy框架對圖片按文件夾分類下載