在上一部落格中,我們已經學會了如何使用Python3爬蟲抓取文字,那麼在本問中,将通過執行個體來教大家如何使用Python3爬蟲批量抓取圖檔。
(1)實戰背景
URL:https://unsplash.com/

上圖的網站的名字叫做Unsplash,免費高清桌面分享網是一個堅持每天分享高清的攝影圖檔的站點,每天更新一張高品質的圖檔素材,全是生活中的景象作品,清新的生活氣息圖檔可以作為桌面桌面也可以應用于各種需要的環境。
看到這麼優美的圖檔,是不是很想下載下傳做桌面呢。每張圖檔我都很喜歡,批量下載下傳吧,不多爬,就下載下傳50張好了。
2)實戰進階
<a>标簽存放超連結,圖檔存放在<img>标簽中!既然這樣,我們截取就Unsplash網站中的一個<img>标簽,分析一下:
<img alt="Snow-capped mountain slopes under blue sky" src="https://images.unsplash.com/photo-1428509774491-cfac96e12253?dpr=1&
可以看到,<img>标簽有很多屬性,有alt、src、class、style屬性,其中src屬性存放的就是我們需要的圖檔儲存位址,我們根據這個位址就可以進行圖檔的下載下傳。
是以爬取過程為:
- 使用requeusts擷取整個網頁的HTML資訊;
- 使用xpath解析HTML資訊,找到所有<img>标簽,提取src屬性,擷取圖檔存放位址;
- 根據圖檔存放位址,下載下傳圖檔。
按這個思路爬取Unsplash試一試,編寫代碼如下:
import requests
if __name__ == '__main__':
url = 'https://unsplash.com/'
req = requests.get(url)
print(req.text)
按照我們的設想,我們應該能找到很多
<img>
标簽。但是我們發現,除了一些
<script>
标簽和一些看不懂的代碼之外,我們一無所獲,一個
<img>
标簽都沒有!
因為這個網站的所有圖檔都是動态加載的!網站有靜态網站和動态網站之分,上一個實戰爬取的網站是靜态網站,而這個網站是動态網站,動态加載有一部分的目的就是為了反爬蟲。
可以使用浏覽器自帶的Networks,它自然會幫我們分析JavaScript腳本執行的内容。
然而事實并沒有這麼簡單,仔細看看,我們會發現,網頁源碼中隻有為數不多的幾個img标簽,也就是說,我們隻能擷取到幾張圖檔的路徑,我們要的可是大量的圖檔,接下來将頁面下滑,會發現img标簽多了起來,很顯然這是一個Ajax[1]動态加載的網站
3)完整代碼如下:
'''
精美圖檔下載下傳
'''
import requests
import json
import time
import random
from contextlib import closing
class Imgdownloader(object):
#初始化
def __init__(self):
self.headers= {
'Referer': 'https://unsplash.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) \
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36',
}
self.base_url = 'https://unsplash.com/napi/photos'
self.img_urls = []
self.page = 0
self.per_page =12
def get_img_urls(self):
'''擷取圖檔連結位址
'''
for i in range(self.per_page):
self.page = self.page+i+1
params={
"page":self.page,
"per_page":self.per_page,
}
res =requests.get(self.base_url,params = params)
#json轉換為字典
res_dict = json.loads(res.text)
for item in res_dict:
url = item['urls']['regular']
self.img_urls.append(url)
#每次擷取一頁連結,随機休眠
time.sleep(random.random())
print("圖檔urls擷取成功")
def img_download(self,urls):
'''
下載下傳圖檔到本地存儲
'''
num = 0
for url in urls:
num = num + 1
res = requests.get(url,headers =self.headers)
img_path = str(num) +".jpg"
with closing(requests.get(url,headers =self.headers,stream = True)) as res:
with open(img_path,'wb') as f:
print("正在下載下傳第{}張照片".format(num))
for chunk in res.iter_content(chunk_size = 1024):
f.write(chunk)
print("{}.jpg 下載下傳成功".format(num))
if __name__ == '__main__':
#圖檔下載下傳對象
imgdl = Imgdownloader()
print("擷取圖檔連結中...")
#對象擷取圖檔連結
imgdl.get_img_urls()
print("開始下載下傳圖檔:")
#下載下傳圖檔
imgdl.img_download(imgdl.img_urls)
print('所有圖檔下載下傳完成')
下載下傳速度還行,有的圖檔下載下傳慢是因為圖檔太大