爬蟲實戰篇---使用Scrapy框架進行汽車之家寶馬圖片下載爬蟲


(1)、前言

Scrapy框架為文件和圖片的下載專門提供了兩個Item Pipeline 它們分別是:

FilePipeline

ImagesPipeline

(2)、使用Scrapy內置的下載方法的好處

1、可以有效避免重復下載

2、方便指定下載路徑

3、方便格式轉換,例如可以有效的將圖片轉換為png 或jpg

4、方便生成縮略圖

5、方便調整圖片大小

6、異步下載,高效率

(3)、較為傳統的Scrapy框架圖片下載方式

1、創建項目:scrapy startproject baoma---cd baoma --創建爬蟲scrapy genspider spider car.autohome.com.cn

2、使用pycharm打開項目

改寫settings.py

不遵守robots協議

設置請求頭

開啟pipelines.py

改寫spider.py

 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 from ..items import BaomaItem
 4 
 5 class SpiderSpider(scrapy.Spider):
 6     name = 'spider'
 7     allowed_domains = ['car.autohome.com.cn']
 8     start_urls = ['https://car.autohome.com.cn/pic/series/65.html']
 9 
10     def parse(self, response):
11         #SelecorList類型
12         uiboxs = response.xpath('//div[@class = "uibox"]')[1:] #第一個我們不需要
13         for uibox in uiboxs:
14             catagory = uibox.xpath('.//div[@class = "uibox-title"]/a/text()').get()
15             urls = uibox.xpath('.//ul/li/a/img/@src').getall()
16             #遍歷列表,並將列表中的某一項執行函數操作,再將函數的返回值以列表的形式返回
17             #map()
18             # for url in urls:
19             #     # url = 'https:' + url
20             #     # print(url)
21             #     #方法二:
22             #     url = response.urljoin(url)
23             #     print(url)
24                 #方法三:
25                 #將列表中的每一項進行遍歷傳遞給lambda表達式,並執行函數中的代碼,再以返回值以列表形式進行返回,結果是map對象,接着使用list轉換為列表
26             urls = list(map(lambda url:response.urljoin(url),urls))
27             item = BaomaItem(catagory = catagory,urls = urls)
28             yield item

改寫pipelines.py

 1 # -*- coding: utf-8 -*-
 2 
 3 # Define your item pipelines here
 4 #
 5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting
 6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
 7 import os
 8 from urllib import request
 9 
10 class BaomaPipeline(object):
11     def __init__(self):
12         self.path = os.path.join(os.path.dirname(__file__), 'images') #os.path.dirname()獲取當前文件的路徑,os.path.join()獲取當前目錄並拼接成新目錄
13         if not os.path.exists(self.path):  # 判斷路徑是否存在
14             os.mkdir(self.path)
15 
16     def process_item(self, item, spider):
17         #分類存儲
18         catagory = item['catagory']
19         urls = item['urls']
20 
21         catagory_path = os.path.join(self.path,catagory)
22         if  not os.path.exists(catagory_path): #如果沒有該路徑即創建一個
23             os.mkdir(catagory_path)
24 
25         for url in urls:
26             image_name = url.split('_')[-1] #以_進行切割並取最后一個單元
27             request.urlretrieve(url,os.path.join(catagory_path,image_name))
28 
29 
30         return item

新建測試py(main.py)

1 #author: "xian"
2 #date: 2018/6/14
3 from scrapy import cmdline
4 cmdline.execute('scrapy crawl spider'.split())

運行結果:(我們成功獲取了以catagory分類並以圖片地址_后的參數作為圖片名的圖片)

Scrapy框架提供了兩個中間件1、下載文件的Files pipeline 和下載圖片的Image pipeline

下載文件的Files pipeline

使用步驟:

1、定義好一個item,然后定義兩個屬性file_urls 和 files . file_urls是用來存儲需要下載的文件的url鏈接,列表類型

2、當文件下載完成后,會把文件下載的相關信息存儲到item的files屬性中。例如:下載路徑,下載url 和文件的效驗碼

3、再配置文件settings.py中配置FILES_STORE,指定文件下載路徑

4、啟動pipeline,在ITEM_PIPELINES中設置scrapy.pipelines.files.FilesPipeline :1

下載圖片的Images Pipeline

使用步驟:

1、定義好一個item,然后定義兩個屬性image_urls 和 images. image_urls是用來存儲需要下載的文件的url鏈接,列表類型

2、當文件下載完成后,會把文件下載的相關信息存儲到item的images屬性中。例如:下載路徑,下載url 和文件的效驗碼

3、再配置文件settings.py中配置FILES_STORE,指定文件下載路徑

4、啟動pipeline,在ITEM_PIPELINES中設置scrapy.pipelines.images.ImagesPipeline :1

(4)、使用Images_pipeline進行圖片下載(還是以汽車之家圖片為例)

改寫settings.py

開啟自己定義的中間件

改寫pipelines,py

 1 # -*- coding: utf-8 -*-
 2 
 3 # Define your item pipelines here
 4 #
 5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting
 6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
 7 import os
 8 from urllib import request
 9 from scrapy.pipelines.images import ImagesPipeline
10 import settings
11 
12 class BaomaPipeline(object):
13     def __init__(self):
14         self.path = os.path.join(os.path.dirname(__file__), 'images') #os.path.dirname()獲取當前文件的路徑,os.path.join()獲取當前目錄並拼接成新目錄
15         if not os.path.exists(self.path):  # 判斷路徑是否存在
16             os.mkdir(self.path)
17 
18     def process_item(self, item, spider):
19         #分類存儲
20         catagory = item['catagory']
21         urls = item['urls']
22 
23         catagory_path = os.path.join(self.path,catagory)
24         if  not os.path.exists(catagory_path): #如果沒有該路徑即創建一個
25             os.mkdir(catagory_path)
26 
27         for url in urls:
28             image_name = url.split('_')[-1] #以_進行切割並取最后一個單元
29             request.urlretrieve(url,os.path.join(catagory_path,image_name))
30 
31 
32         return item
33 
34 
35 class BMWImagesPipeline(ImagesPipeline):  # 繼承ImagesPipeline
36     # 該方法在發送下載請求前調用,本身就是發送下載請求的
37     def get_media_requests(self, item, info):
38         request_objects = super(BMWImagesPipeline, self).get_media_requests(item, info)  # super()直接調用父類對象
39         for request_object in request_objects:
40             request_object.item = item
41         return request_objects
42 
43     def file_path(self, request, response=None, info=None):
44         path = super(BMWImagesPipeline, self).file_path(request, response, info)
45         # 該方法是在圖片將要被存儲時調用,用於獲取圖片存儲的路徑
46         catagory = request.item.get('catagory')
47         images_stores = settings.IMAGES_STORE #拿到IMAGES_STORE
48         catagory_path = os.path.join(images_stores,catagory)
49         if not os.path.exists(catagory_path): #判斷文件名是否存在,如果不存在創建文件
50             os.mkdir(catagory_path)
51         image_name = path.replace('full/','')
52         image_path = os.path.join(catagory_path,image_name)
53         return image_path

運行結果展示:

通過對比我們可以直觀感受到下載速度明顯提高。

下面我們對圖片進行優化,獲取高清圖片

通過分析縮略圖和高清圖的url,我們發現縮略圖只是多了t_罷了

縮略圖地址:https://car3.autoimg.cn/cardfs/product/g24/M08/2F/9E/t_autohomecar__wKgHIVpogfqAIlTbAAUzcUgKoGY701.jpg

高清圖地址:https://car3.autoimg.cn/cardfs/product/g24/M08/2F/9E/autohomecar__wKgHIVpogfqAIlTbAAUzcUgKoGY701.jpg

(5)、下面我們獲取所有的高清圖片

傳統思路如下:找到更多獲取接口的url,進入詳情頁--找分頁接口(顯然這種情況會大大提高我們的工作量,下面我們使用Scrapy框架中的CrawlSpider進行爬取,因為CrawlSpider只要指定響應的規則,爬蟲會自動進行爬取,省事省力!)

我們首先分析下url的規律:

https://car.autohome.com.cn/pic/series/65-1.html(更多的第一頁url)

https://car.autohome.com.cn/pic/series/65-1-p2.html(更多的第二頁url)

改寫spider.py

 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 from scrapy.spiders import CrawlSpider ,Rule#導入CrawlSpider模塊 需改寫原來的def parse(self,response)方法
 4 from scrapy.linkextractor import LinkExtractor #導入鏈接提取模塊
 5 from ..items import BaomaItem
 6 
 7 
 8 class SpiderSpider(CrawlSpider):
 9     name = 'spider'
10     allowed_domains = ['car.autohome.com.cn']
11     start_urls = ['https://car.autohome.com.cn/pic/series/65.html']
12 
13     rules = {
14         Rule(LinkExtractor(allow=r'https://car.autohome.com.cn/pic/series/65.+'),callback= 'parse_page',follow=True),
15 
16     } #如需要進行頁面解釋則使用callback回調函數 因為有下一頁,所以我們需要跟進,這里使用follow令其為True
17 
18 
19     def parse_page(self, response): #頁面解析函數
20         catagory = response.xpath('//div[@class = "uibox"]/div/text()').get()
21         srcs = response.xpath('//div[contains(@class,"uibox-con")]/ul/li//img/@src').getall()
22         srcs = list(map(lambda x:x.replace('t_',''),srcs)) #map(函數,參數二),將參數二中的每個都進行函數計算並返回一個列表
23         # urls = {}
24         # for src in srcs:
25         #     url = response.url.join(src)
26         #     urls.append(url)
27         srcs = list(map(lambda x:response.urljoin(x),srcs))
28         yield BaomaItem(catagory=catagory,image_urls = srcs)

運行結果(展示):(我們成功獲取了高清圖片到本地)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM