【Scrapy學習心得】爬蟲實戰三(異步下載寶馬5系高清圖片)

【Scrapy學習心得】爬蟲實戰三(異步下載寶馬5系高清圖片)

聲明:僅供技術交流,請勿用於非法用途,如有其它非法用途造成損失,和本博客無關

爬取的網站:汽車之家的寶馬5系所有高清圖片 點擊跳轉

一、配置環境

  • python3.7
  • pycharm
  • Scrapy1.7.3
  • win10
  • pymysql

二、準備工作

  • cmd命令行中進入需要創建項目的目錄運行scrapy startproject hehe
  • 創建成功後繼續執行cd hehe
  • 然後執行scrapy genspider bmw car.autohome.com.cn
  • 最後在spider文件夾下可以看到剛創建的bmw.py爬蟲文件

三、分析網頁


不難發現,寶馬5系的那些車身外觀啊、中控方向盤啊等等分類都在這個uiboxdiv標籤中,除了全景看車那個,我這都把各個分類中每張圖片對應的高清url地址都要拿到,我先把每個分類的url地址給拿到,

然後再通過翻頁拿到全部圖片的高清圖片地址,就可以輕鬆拿到所有寶馬5系的高清圖片了,完美!

先放上爬取的部分高清圖片

所以總共我要爬取的內容有:

  • 分類的名稱以及其具體的url地址
  • 所有高清圖片

查找元素的那些操作我就不放上來了,因爲沒什麼難度的,會來學scrapy框架的同學肯定是跟我一樣那些什麼requests啊,urllib啊,selenium啊等等都是用膩了纔來的,是吧

四、爬取數據

下面先定義item.py文件:

import scrapy

class HeheItem(scrapy.Item):
    title = scrapy.Field() #分類名稱
    url = scrapy.Field()   #分類的具體地址
    gq_url = scrapy.Field()  #高清圖片的地址
    image_urls = scrapy.Field()   #真正要去請求的獲取高清圖片的地址

下面直接放上bmw.py的代碼:

# -*- coding: utf-8 -*-
import scrapy
from copy import deepcopy
from hehe.items import HeheItem

class BmwSpider(scrapy.Spider):
    name = 'bmw'
    allowed_domains = ['car.autohome.com.cn']
    start_urls = ['https://car.autohome.com.cn/pic/series/65.html#pvareaid=3454438']

    def parse(self, response):
        uibox_list=response.xpath('//div[@class="uibox"]')[1:]  #去掉全景觀車
        for uibox in uibox_list:
            item=HeheItem()
            item['title']=uibox.xpath('./div[@class="uibox-title"]/a/text()').get()
            item['url'] = uibox.xpath('./div[@class="uibox-title"]/a/@href').get()
            item['url']=response.urljoin(item['url'])
            #下面去請求進入到分類的地址當中
            yield scrapy.Request(
                item['url'],
                callback=self.parse_list,
                meta={'item':deepcopy(item)}
            )

    def parse_list(self,response):
        item=response.meta['item']
        li_list=response.xpath('//div[@class="uibox-con carpic-list03 border-b-solid"]/ul/li')
        for li in li_list:
            item['gq_url']=response.urljoin(li.xpath('./a/@href').get())
            #下面去請求進入高清圖片的地址當中
            yield scrapy.Request(
                item['gq_url'],
                callback=self.parse_gq,
                meta={'item':deepcopy(item)}
            )
        #下面進行翻頁的操作
        next_page=response.xpath('//a[@class="page-item-next"]/@href').get()
        if next_page != 'javascript:void(0);':  #當有下一頁的時候纔去翻頁
            next_page=response.urljoin(next_page)
            yield scrapy.Request(
                next_page,
                callback=self.parse_list,  #翻頁操作時的callback函數是自己
                meta={'item':item}
            )

    def parse_gq(self,response):
        item=response.meta['item']
        item['image_urls']=response.xpath('//img[@id="img"]/@src').getall()
        item['image_urls']=[response.urljoin(item['image_urls'][0])]  #需要把它改成一個列表,不然後面用urlretrieve會報錯
        yield item

五、保存數據(同步下載圖片)

這裏先用傳統的保存圖片的方法來保存,修改pipeline.py文件如下:

# -*- coding: utf-8 -*-
import os
from urllib.request import urlretrieve  #用來下載圖片

class HehePipeline(object):
    def __init__(self):   #下面是創建保存圖片的文件夾images
        self.path=os.path.join(os.path.dirname(os.path.dirname(__file__)),'images')
        if not os.path.exists(self.path):
            os.mkdir(self.path)

    def process_item(self, item, spider):
        if spider.name == 'bmw':
            cate=item['title']
            url=item['image_urls']
            cate_path=os.path.join(self.path,cate)
            #按分類來保存圖片
            if not os.path.exists(cate_path):
                os.mkdir(cate_path)
            name=url.split('__')[-1] #取url後面部分來作爲圖片的名稱
            urlretrieve(url, os.path.join(cate_path, name))

現在我們的爬蟲大致已經是寫完了,不過我還要修改一下setting.py文件的一些設置,需要增加的語句有:

LOG_LEVEL='WARNING' #設置日誌輸出級別
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'  #設置請求頭
ROBOTSTXT_OBEY = False  #把這個設置成False,就不會去請求網頁的robots.txt,因爲不改爲False的話,scrapy就會去訪問該網站的robots.txt協議,如果網站沒有這個協議,那麼它就不會去訪問該網站,就會跳過,進而爬不到數據
ITEM_PIPELINES = {
   'hehe.pipelines.HehePipeline': 300,
}

最後在cmd中先進入到這個項目的根目錄下,即有scrapy.cfg文件的目錄下,然後輸入並運行scrapy crawl bmw,最後靜靜等待就行了,不過下載的速度的確是有點慢

六、保存數據(異步下載圖片)

然後這裏採用scrapy內置的pipeline來進行保存圖片,用這個來保存圖片呢有下面幾個好處:

  1. scrapy本身就有url去重的功能,所以就不會出現重複下載同一張圖片的情況
  2. 它採用的是異步下載,下載速度大大提高
  3. 而且它還會自動把圖片保存爲合適的格式
  4. 等等等等

下面在pipeline.py文件中添加一個類,代碼如下:

# -*- coding: utf-8 -*-
import os
from scrapy.pipelines.images import ImagesPipeline  #使用scrapy自帶的pipeline
from hehe import settings #導入配置文件

#只需重新複寫以下兩個方法就行
class HahaPipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        request_objs=super(HahaPipeline,self).get_media_requests(item,info)
        for request_obj in request_objs:
            request_obj.item=item
        return request_objs

    def file_path(self, request, response=None, info=None):
        #這個方法是圖片將要被存儲的時候調用,來獲取圖片的存儲路徑
        path=super(HahaPipeline,self).file_path(request,response,info)
        cate=request.item.get('title')
        images_store=settings.IMAGES_STORE  #獲取配置文件當中的文件路徑,如果不存在,會自動創建
        cate_path=os.path.join(images_store,cate)
        if not os.path.exists(cate_path):
            os.mkdir(cate_path)
        name=path.replace('full/','')  #去掉scrapy中這個pipeline自己定義的文件夾路徑,這裏你們可以去看看源碼就知道了
        images_path=os.path.join(cate_path,name) #重新定義文件夾路徑
        return images_path #返回自定義的圖片存放路徑

同樣需要在setting.py文件中設置修改pipeline才能把這個新的pipeline給生效,如下添加一行並把之前的給註釋掉,並且增加保存文件的路徑一行:

import os
IMAGES_STORE=os.path.join(os.path.dirname(os.path.dirname(__file__)),'images')
ITEM_PIPELINES = {
   # 'hehe.pipelines.HehePipeline': 300,
   'hehe.pipelines.HahaPipeline': 300,
}

把之前下載的圖片刪除,重新運行一遍這個爬蟲,會發現速度明顯比之前要快得多,這就是異步下載的威力啊哈哈

寫在最後

怎麼說呢,當你試過這兩種下載圖片的方法之後,你會恍然大悟,會喜歡上scrapy框架,但是,其實那些異步下載啊、多線程啊什麼的,如果有能力自己敲代碼也是能夠實現的,但是,我又覺得,既然scrapy已經幫你弄好了一整套可用的東西,你非要去自己編寫,那不就是重複造輪子麼,除非你想發展爲爬蟲架構師的那種級別,一般我們還是用別人的東西,學會用別人的東西就已經很不錯了我覺得。而且我又覺得,當我們使用的多了之後,估計自然而然地也就清楚地知道那些框架是怎麼回事了吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章