Scrapy爬取汽車之家某品牌圖片
需求
爬取汽車之家某品牌的汽車圖片
目標url
https://car.autohome.com.cn/photolist/series/52880/6957393.html#pvareaid=3454450
頁面分析
最開始出現(xiàn)的全景的圖片不是爬取的范疇。每一頁有90張圖片,還要做一個翻頁的處理。

找到一張圖片,點右鍵,檢查,可以發(fā)現(xiàn)每一張圖片都存放在一個li標簽內(nèi),所有的li標簽都存放在ul標簽內(nèi),圖片的鏈接信息存放在li標簽下a標簽里的img標簽內(nèi),復制src后面的地址,在新的網(wǎng)址中可以打開圖片,說明存放的是圖片的url地址。在打開圖片的網(wǎng)址中,可以發(fā)現(xiàn)瀏覽器對圖片地址進行了補全的操作。
下面要判斷網(wǎng)頁是動態(tài)還是靜態(tài)加載出來的,對img標簽進行判斷,看是否存放在源碼中,點擊右鍵,檢查網(wǎng)頁源碼,可以看到img里圖片的url信息在源碼中存在,所以目標url即為要爬取的url
下面進行翻頁的處理。第2頁的url:https://car.autohome.com.cn/photolist/series/65/p2/ 第3頁的url:https://car.autohome.com.cn/photolist/series/65/p3/ 這時我們把p3改為p1,發(fā)現(xiàn)也可以訪問第1頁 第1頁的url:https://car.autohome.com.cn/photolist/series/65/p1/
實現(xiàn)步驟
創(chuàng)建scrapy框架,用https://car.autohome.com.cn/photolist/series/52880/6957393.html#pvareaid=3454450,作為目標url進行訪問。
import?scrapy
from?pic.items?import?PicItem
class?AutoSpider(scrapy.Spider):
????name?=?'auto'
????allowed_domains?=?['car.autohome.com.cn']
????start_urls?=?['https://car.autohome.com.cn/photolist/series/52880/6957393.html#pvareaid=3454450']
????def?parse(self,?response):
????????lis?=?response.xpath('//ul[@id="imgList"]/li')
????????for?li?in?lis:
????????????item?=?PicItem()
????????????item['src']?=?'http:'?+?li.xpath('./a/img/@src').get()
????????????print(item)
這里我們用xpath進行尋找,id="imgList"在源碼中存在,可以直接對id后面的路徑進行xpath??梢缘玫降谝豁摰膱D片信息,我們嘗試用得到的第一頁的url進行訪問。https://car.autohome.com.cn/photolist/series/65/p1/,訪問之后我們發(fā)現(xiàn)獲取的最后幾個圖片的地址是一樣的。
這時我們?nèi)ピ创a中看一下。
我們發(fā)現(xiàn)有些圖片的的地址在src2中,直接用src獲取不到圖片的真正地址。這個時候要進行一個判斷。
????????for?li?in?lis:
????????????item?=?PicItem()
????????????#?如果有src2屬性就直接獲取,否則獲取src的值
????????????try:
????????????????item['src']?=?'http:'?+?li.xpath('./a/img/@src2').get()
????????????except:
????????????????item['src']?=?'http:'?+?li.xpath('./a/img/@src').get()
????????????print(item)
先對src2進行判斷,如果有就用里面的內(nèi)容,否則就用src里的內(nèi)容,這樣得到圖片的url就是正常的了。在scrapy里有一種拼接的方法,但是在沒有掌握規(guī)律之前,慎用。
class?AutoSpider(scrapy.Spider):
????name?=?'auto'
????allowed_domains?=?['car.autohome.com.cn']
????start_urls?=?['https://car.autohome.com.cn/photolist/series/65/p1/']
????def?parse(self,?response):
????????page_url?=?'//car.autohome.com.cn/photolist/series/65/p2/'
????????print(response.urljoin(page_url))
輸出的結(jié)果為
https://car.autohome.com.cn/photolist/series/65/p2/
實現(xiàn)了url地址的拼接。也可以用os模塊實現(xiàn)路徑的拼接
import?os
path?=?os.path.join('D:\PycharmProjects\爬蟲\day25\pic\images','xxx.jpg')
print(path)
拼接之后的結(jié)果為
D:\PycharmProjects\爬蟲\day25\pic\images\xxx.jpg
也可以用當前系統(tǒng)的路徑進行拼接
#?打印當前運行的py文件的完整路徑
print(__file__)???#?D:/PycharmProjects/爬蟲/day25/pic/demo.py
#os.path.dirname()?返回文件的路徑,簡單理解為往上退了以及目錄
print(os.path.dirname(__file__))??#?D:/PycharmProjects/爬蟲/day25/pic
#?再往上退一級目錄
print(os.path.dirname(os.path.dirname(__file__)))
相當于從當前路徑退了兩級,運行的結(jié)果是
D:/PycharmProjects/爬蟲/day25
第一種用pipelines保存圖片
下面要對爬取的圖片進行保存操作,在爬蟲文件中把print(item) 改為 yield item,對pipelines進行保存圖片程序的編寫。
from?urllib?import?request
import?os
class?PicPipeline:
????def?process_item(self,?item,?spider):
????????#?print(item['src'])
????????src?=?item['src']
????????#?對圖片進行保存的文件名,用__分割,取后面的字符,不會重復
????????img_name?=?src.split('__')[-1]
????????#?在pic下創(chuàng)建images文件夾用于保存圖片
????????#?現(xiàn)在要進行的操作是?把圖片保存到images文件夾
????????#?文件夾的路徑
????????file_path?=?os.path.join(os.path.dirname(os.path.dirname(__file__)),?'images')
????????#?圖片的路徑
????????img_path?=?os.path.join(file_path,?img_name)
????????#?print(img_path)
????????#?保存圖片,第一個參數(shù)為請求的url,第二個參數(shù)是保存的路徑
????????print(f"正在下載{img_name}圖片")
????????request.urlretrieve(src,?img_path)
????????return?item
第二種用Images Pipeline下載圖片
使用images pipeline下載文件步驟:
定義好一個Item,然后在這個item中定義兩個屬性,分別為image_urls以及images。image_urls是用來存儲需要下載的文件的url鏈接,需要給一個列表1. 當文件下載完成后,會把文件下載的相關(guān)信息存儲到item的images屬性中。如下載路徑、下載的url和圖片校驗碼等1. 在配置文件settings.py中配置IMAGES_STORE,這個配置用來設置文件下載路徑1. 啟動pipeline:在ITEM_PIPELINES中設置scrapy.pipelines.images.ImagesPipeline:1 代碼實施: item.py里增加 image_urls = scrapy.Field() images = scrapy.Field()1. 爬蟲文件中item[‘src’]改為item[‘image_urls’],后面的url加上列表1. 在setting里做配置
??ITEM_PIPELINES?=?{
???#?'pic.pipelines.PicPipeline':?300,
????'scrapy.pipelines.images.ImagesPipeline':?1
}
import?os
#?文件夾的路徑
file_path?=?os.path.join(os.path.dirname(os.path.dirname(__file__)),?'images')
#?配置文件的下載路徑(文件路徑)
IMAGES_STORE?=?file_path
運行程序即可,爬取的圖片保存在images文件夾下的full文件夾里,但是圖片的名字是隨機生成的。我們可以嘗試看一下原因。from scrapy.pipelines.images import ImagesPipeline,導入ImagesPipeline類,鼠標左鍵點擊進入源碼中,在178行左右有個file_path函數(shù)
????def?file_path(self,?request,?response=None,?info=None,?*,?item=None):
?????#?哈希生成32位的十六進制數(shù)據(jù)作為圖片的名字
????????image_guid?=?hashlib.sha1(to_bytes(request.url)).hexdigest()
????????#?返回文件夾下full文件夾內(nèi),圖片的名字是哈希隨機生成的
????????return?f'full/{image_guid}.jpg'
哈希的簡單使用
import?hashlib
h?=?hashlib.sha1()
print(h)??#?返回哈希對象?<sha1?HASH?object?@?0x00000244B4A15760>
h.update('images'.encode('utf-8'))??#?對數(shù)據(jù)加密
#?hexdigest()返回的是十六進制的字符串
print(h.hexdigest())??#?19f49d852660fe0a079cbf95c3efb34ba88de911
