一、前言
1.1 需求來源
很多英雄聯(lián)盟的元老級玩家都認可 LOL 的美工做得很好,不乏玩家將英雄的皮膚設(shè)為手機、電腦的壁紙或個人社交賬號的頭像。
作為 LOL 發(fā)燒友,如果想每天換一張電腦壁紙,該如何爬取 LOL 全英雄的全部皮膚呢?由于皮膚數(shù)量過多,最好能按英雄名分文件夾存儲,找起來也比較方便。
1.2 準備工作
python:3.11.3(≥3.7)
selenium 庫:4.9.1
Firefox 瀏覽器:114.0.2 (64 位)
geckodriver:geckodriver-v0.33.0-win64.zip
如何安裝 geckodriver?
1.3 思路解析
LOL 英雄界面上有全部英雄的信息,點擊頭像圖片,可以進入個英雄主頁,點擊主頁下的一排小圖標,可以切換不同的皮膚,右鍵皮膚可以查看高清皮膚的下載鏈接。
其中,英雄主頁可以由英雄的 id (后端設(shè)定)來映射;高清皮膚的鏈接跟小圖的鏈接可以互相轉(zhuǎn)換。
1.4 算法流程設(shè)計
? 1). 從 LOL 英雄界面獲取每個英雄的全名和 id
? 2). 遍歷全部英雄,對每個英雄:
? ① 根據(jù)全稱創(chuàng)建文件夾
? ② 根據(jù) id 定位到主頁面
? ③ 獲取全部皮膚小圖標的鏈接
? ④ 將小圖標鏈接轉(zhuǎn)化為高清皮膚鏈接
? ⑤ 將高清皮膚保存到該英雄的文件夾中
1.5 算法實現(xiàn)方案
? 1). 使用列表保存數(shù)據(jù)用于遍歷
? 2). 使用 webdriver(geckodriver)獲取網(wǎng)頁信息、定位元素、下載資源
? 3). 使用 try-except 處理異常情景
? 4). 使用 time.sleep 反爬
? 5). 使用 str.replace 替換 “K//DA” 中特殊字符
二、代碼解析
2.1 獲取全部英雄姓名、id
使用 “imgtextlist” 類定位到全部英雄的元素塊,再獲取所有 “l(fā)i” 標簽的信息,存入列表中等待進一步解析。
# 獲取全部英雄概覽信息
def getHeros(driver):
# 英雄聯(lián)盟英雄信息前置界面
driver.get('https://lol.qq.com/data/info-heros.shtml')
# 獲取全部英雄的信息概覽
heros_res = driver.find_element(By.CLASS_NAME, "imgtextlist")
# 獲取每個英雄信息的列表
heros = heros_res.find_elements(By.TAG_NAME, "li")
return heros
進一步解析可以獲得英雄的全稱和 id ,這里使用兩個函數(shù)分別返還結(jié)果:
# 獲取英雄名稱,用于單獨建立文件夾存儲
def getHerosName(heros):
hero_name = [] # 記錄英雄全名,如“德邦總管 趙信”
for h in heros:
hero_name.append(h.find_element(By.TAG_NAME, "a").get_attribute("title")) # 獲取英雄全名
print("hero_name:", hero_name)
return hero_name
# 獲取英雄排名id,用于后續(xù)獲取皮膚圖片等
def getHerosId(heros):
hero_id = [] # 記錄英雄的排名id
for h in heros:
hero_href = h.find_element(By.TAG_NAME, "a").get_attribute("href") # 獲取英雄個人鏈接
hero_id.append(hero_href.split('=')[1]) # 獲取英雄的排名id
return hero_id
注意:獲取id是很重要的,因為id并不是和英雄的推出順序是一致的,如新英雄明燭的id是902,而LOL顯然沒有那么多英雄。獲取皮膚是必須要有英雄id的。(不知道這是不是官方刻意設(shè)置的一種反爬機制?)也可以直接保存英雄的跳轉(zhuǎn)鏈接進行跳轉(zhuǎn)。
2.2 遍歷全部英雄
total_num = len(hero_name)
for i in range(total_num):
2.2.1 創(chuàng)建各英雄的文件夾
# 為每一個英雄單獨創(chuàng)建文件夾,來保存皮膚
def createPath(name):
global savePath
filepath = f"{savePath}{name}\\" # 為每一個英雄單獨創(chuàng)建一個路徑,以其全名命名
if not os.path.exists(filepath):
os.makedirs(filepath)
print(filepath + "文件夾創(chuàng)建成功!")
2.2.2 根據(jù) id 定位到主頁面
根據(jù) id 跳轉(zhuǎn)到英雄主界面:
url = "https://lol.qq.com/data/info-defail.shtml?id=" + str(n) # 根據(jù) id 可以獲取英雄的個人鏈接
進而可以定位到小圖標及其鏈接:
driver.get(url)
skins_res = driver.find_element(By.ID, "skinNAV") # 定位到皮膚欄
skins = skins_res.find_elements(By.TAG_NAME, "img") # 獲取小圖標的列表
for skin in skins:
skin_name = skin.get_attribute("alt")
skin_link_small = skin.get_attribute("src") # 獲取每個小圖的鏈接
# https://game.gtimg.cn/images/lol/act/img/skin/small_0b940af1-bd04-4f9a-a909-427cabea21b1.jpg
2.2.3 轉(zhuǎn)換小圖標鏈接為高清圖鏈接
小圖標的鏈接為:
?https://game.gtimg.cn/images/lol/act/img/skin/small_0b940af1-bd04-4f9a-a909-427cabea21b1.jpg
高清圖的鏈接為:
?https://game.gtimg.cn/images/lol/act/img/skin/big_0b940af1-bd04-4f9a-a909-427cabea21b1.jpg
通過簡單的字符串替換即可實現(xiàn):
skin_link_big = str(skin_link_small).replace("small", "big") # 替換為大圖的鏈接
# https://game.gtimg.cn/images/lol/act/img/skin/big_0b940af1-bd04-4f9a-a909-427cabea21b1.jpg
2.2.4 保存高清皮膚圖片
給圖片確定存儲路徑時,要考慮 “K/DA” 字符串的影響,替換掉 “/” 為 “” 避免識別為路徑而報錯:
filename = f"{savePath}{hero_name[i]}\\{str(skin_name).replace('/', '')}.jpg" # 防止 K/DA 下載出錯
之后就可以開始下載了:文章來源:http://www.zghlxwxcb.cn/news/detail-613748.html
try:
urlretrieve(skin_link_big, filename=filename)
except urllib.error.ContentTooShortError:
driver.sleep(5)
urlretrieve(skin_link_big, filename=filename)
except:
print("未知錯誤!")
print(skin_name + "圖片下載完成!") # 輸出提示:英雄的該個皮膚圖片下載完成
三、運行截圖
運行過程中打印提示數(shù)據(jù):
文件夾中查看保存皮膚:文章來源地址http://www.zghlxwxcb.cn/news/detail-613748.html
四、完整代碼
import os
import time
import urllib
from selenium import webdriver
from urllib.request import urlretrieve
from selenium.webdriver.common.by import By
# 模擬請求頭
user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/" \
"605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15"
# 配置 webdriver
opt = webdriver.FirefoxOptions()
opt.add_argument('--user-agent=%s' % user_agent)
# opt.add_argument("--headless") # 開啟此選項,瀏覽器不會顯示動作
# 獲取全部英雄概覽信息
def getHeros(driver):
# 英雄聯(lián)盟英雄信息前置界面
driver.get('https://lol.qq.com/data/info-heros.shtml')
# 獲取全部英雄的信息概覽
heros_res = driver.find_element(By.CLASS_NAME, "imgtextlist")
# 獲取每個英雄信息的列表
heros = heros_res.find_elements(By.TAG_NAME, "li")
return heros
# 獲取英雄名稱,用于單獨建立文件夾存儲
def getHerosName(heros):
hero_name = [] # 記錄英雄全名,如“德邦總管 趙信”
for h in heros:
hero_name.append(h.find_element(By.TAG_NAME, "a").get_attribute("title")) # 獲取英雄全名
print("hero_name:", hero_name)
return hero_name
# 獲取英雄排名id,用于后續(xù)獲取皮膚圖片等
def getHerosId(heros):
hero_id = [] # 記錄英雄的排名id
for h in heros:
hero_href = h.find_element(By.TAG_NAME, "a").get_attribute("href") # 獲取英雄個人鏈接
hero_id.append(hero_href.split('=')[1]) # 獲取英雄的排名id
return hero_id
# 為每一個英雄單獨創(chuàng)建文件夾,來保存皮膚
def createPath(name):
global savePath
filepath = f"{savePath}{name}\\" # 為每一個英雄單獨創(chuàng)建一個路徑,以其全名命名
if not os.path.exists(filepath):
os.makedirs(filepath)
print(filepath + "文件夾創(chuàng)建成功!")
# 獲取英雄皮膚,規(guī)避反爬機制,并進行異常處理
def getAndSaveSkins(driver, hero_name, hero_id):
global savePath
# 遍歷全部英雄
total_num = len(hero_name)
for i in range(total_num):
createPath(hero_name[i]) # 為每個英雄單獨開辟一個文件夾
n = hero_id[i] # 提取英雄對應(yīng)的id。注意:id 和 name 列表順序并不是一一對應(yīng)的,因此有必要單獨獲取
driver.implicitly_wait(10)
url = "https://lol.qq.com/data/info-defail.shtml?id=" + str(n) # 根據(jù) id 可以獲取英雄的個人鏈接
driver.get(url)
skins_res = driver.find_element(By.ID, "skinNAV") # 定位到皮膚欄
skins = skins_res.find_elements(By.TAG_NAME, "img") # 獲取小圖標的列表
for skin in skins:
skin_name = skin.get_attribute("alt")
skin_link_small = skin.get_attribute("src") # 獲取每個小圖的鏈接
# https://game.gtimg.cn/images/lol/act/img/skin/small_0b940af1-bd04-4f9a-a909-427cabea21b1.jpg
skin_link_big = str(skin_link_small).replace("small", "big") # 替換為大圖的鏈接
# https://game.gtimg.cn/images/lol/act/img/skin/big_0b940af1-bd04-4f9a-a909-427cabea21b1.jpg
filename = f"{savePath}{hero_name[i]}\\{str(skin_name).replace('/', '')}.jpg" # 防止 K/DA 下載出錯
try:
urlretrieve(skin_link_big, filename=filename)
except urllib.error.ContentTooShortError:
driver.sleep(5)
urlretrieve(skin_link_big, filename=filename)
except:
print("未知錯誤!")
print(skin_name + "圖片下載完成!") # 輸出提示:英雄的該個皮膚圖片下載完成
print("************" + hero_name[i] + "全部圖片下載完畢!************\n") # 輸出提示:該英雄的全部高清皮膚下載完成
# time.sleep(2) # 設(shè)置時間間隔,規(guī)避反爬機制
if __name__ == "__main__":
savePath = "D:\\lolSkins\\"
driver = webdriver.Firefox(options=opt) # 啟動 webdriver
# 如果 driver 文件沒有放在系統(tǒng)路徑下,可以指定文件路徑,也可以不帶“.exe”
# driver = webdriver.Firefox(executable_path='D:/driver/geckodriver.exe', options=opt)
# 新版 selenium 推薦使用 service 寫法。個人推薦第一種,把 webdriver 放在系統(tǒng)路徑下
# service = Service(executable_path=executable_path='D:/driver/geckodriver.exe')
# driver = webdriver.Firefox(service=service,options=opt)
driver.implicitly_wait(10) # 設(shè)置界面等待的最長時間
heros = getHeros(driver) # 獲取英雄信息概覽
hero_name = getHerosName(heros) # 獲取英雄名,用于存儲皮膚
hero_id = getHerosId(heros) # 獲取英雄id,用于爬取皮膚
getAndSaveSkins(driver, hero_name, hero_id) # 獲取皮膚并保存到對應(yīng)的文件夾中
PS:請勿將此方法用于商業(yè)行為,在法律準許的范圍內(nèi)合理使用互聯(lián)網(wǎng)資源!更多 python 有趣應(yīng)用,敬請關(guān)注后續(xù)更新~
到了這里,關(guān)于【python+selenium】LOL全英雄全皮膚爬蟲--給電腦每天換張壁紙的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!