Python 爬虫实战 | 完美爬取LOL全英雄皮肤高清原画 JavaScript动态网页
Github项目地址 https://github.com/xylon666/Xylon_Code
爬取结果展示: 全原画+皮肤名称分类
所需环境
IDE:Pycharm
第三方库:requests,PIL
浏览器:Chrome
爬取目标:
LOL官网皮肤原画 https://lol.qq.com/data/info-heros.shtml#Navi
一、分析页面
与常规的静态网页不同,LOL官网是借由JavaScript脚本在客户端执行后才会展示完整页面的动态网页,直接使用requests请求获得的页面是没有英雄信息的,因此我们要采取一定的方案
鼠标右键原画检查页面,可以看到皮肤原画地址就在眼前
展开后发现原画的地址格为://ossweb-img.qq.com/images/lol/web201310/skin/big+皮肤ID+.jpg
那么我们就要考虑如何获取所有英雄的皮肤ID以及相关信息了
回到全部英雄页面,F12检查元素-Network-JS,找到一个champion.js文件,里面包含全部英雄的id和英文名
可以看到266就是剑魔的ID
当然,最终要有英雄中文名称和皮肤名称,光有id和英文名是不够的
再进入剑魔页面,检查元素,可以找到Aatrox.js
在网页中打开,可以看到剑魔的个人信息,id、英文名、中文名(Unicode编码)、称号、皮肤编号以及名称一应俱全
注意到页面地址为:https://lol.qq.com/biz/hero/Aatrox.js
也就是说,通过 "https://lol.qq.com/biz/hero/"+英雄英文名+".js" 我们可以访问任何一个英雄的全部信息,进而获取原画链接和名称将其下载下来
所以爬取思路就是:
1.获取champion.js里英雄的英文名称信息
2.访问"https://lol.qq.com/biz/hero/"+英雄英文名+".js",获得英雄具体信息
3.访问"//ossweb-img.qq.com/images/lol/web201310/skin/big"+皮肤ID+".jpg"下载原画
那么,开始写代码吧
二、获取英文名称
下载champion.js至本地
#encoding = 'utf-8'
import requests,json,os
from PIL import Image
from io import BytesIO
url = 'https://lol.qq.com/biz/hero/champion.js'
headers = {
"user-agent":"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36",
}
res = requests.get(url,headers = headers )
res.encoding = 'gbk'
html = res.text
print(html)
出去开头部分,剩下的就是字典类型,为了方便操作,我们将其处理为json类型
data = json.loads("{"+res.text.strip("if(!LOLherojs)var LOLherojs={};LOLherojs.champion=")+"}")
#删去开头部分
print(data)
通过字典查询可以方便快捷地提取英文名,以及中文名称,英文名进行下一步提取英雄完整信息,中文名称用于创建原画文件夹以及文件名
hero_names = data.get("data").keys()
print(hero_names)
heroid_list = []
hero_cnnames = []
for hero_name in hero_names:
heroid_list.append(hero_name)
#print(heroid_list)
for heroid in heroid_list:
#print(heroid)
first_name = data.get("data").get(heroid).get("name")
second_name = data.get("data").get(heroid).get("title")
hero_cnname = first_name + " " + second_name
hero_cnnames.append(hero_cnname)
print(hero_cnnames)
三、获取皮肤ID
有了英文名,我们可以访问"https://lol.qq.com/biz/hero/"+英雄英文名+".js"来获取皮肤ID和名称
for i in range(len(heroid_list)):
id = heroid_list[i]
hero_url = 'https://lol.qq.com/biz/hero/' + id + '.js'
res = requests.get(hero_url, headers=headers)
data = json.loads("{" + res.text.strip("if(!LOLherojs)var LOLherojs={champion:{}};LOLherojs.champion." + id + "=") + "}")
# print(data)
skins = data.get("data").get("skins")
skin_ids = []
skin_names = []
skin_urls = []
for skin in skins:
skin_names.append(skin.get("name"))
skin_ids.append(skin.get("id"))
skin_names[0] = hero_cnnames[i] # 将默认皮肤default的名称改为英雄名称
#print(skin_names)
四、下载原画
从列表skin_ids中获取皮肤ID,组合原画地址再下载
自己在尝试下载的时候,发现K/DA系列一直下载失败,原来是 / 符号影响了文件路径的创建,所以加了一条try把斜杠删掉
for skin_id in skin_ids:
skin_url = "https://ossweb-img.qq.com/images/lol/web201310/skin/big" + skin_id + ".jpg"
skin_urls.append(skin_url)
for j in range(len(skin_ids)):
filename = "D:\\LOL\\" + hero_cnnames[i] + "\\" + skin_names[j] + ".jpg" #文件名
filepath = "D:\\LOL\\" + hero_cnnames[i] + "\\" #文件路径
if not os.path.exists(filepath): #若文件夹路径不存在则新建一个
os.makedirs(filepath)
try:
res = requests.get(skin_urls[j])
image = Image.open(BytesIO(res.content))
image.save(filename)
print('成功下载' + skin_names[j] + '.jpg')
except:
sname = skin_names[j].replace('/', '')
filename = "D:\\LOL\\" + hero_cnnames[0] + "\\" + sname + ".jpg"
res = requests.get(skin_urls[j])
image = Image.open(BytesIO(res.content))
image.save(filename)
print('成功下载' + skin_names[j] + '.jpg')