上篇文章,說到了,爬取LOL英雄皮膚的高清圖片,最近有事,也沒怎麼去研究,因此,如今纔去看了下,而且寫了Python腳原本抓取皮膚圖片。須要說明一下,這個腳本有部分英雄沒有抓取到,可是具體緣由,我目前還沒搞懂,我是至關納悶的。你們有興趣的,能夠看看後面遺留問題,一塊兒研究下。html
我先查看了network,並無發現有可用的API;而後又用bs4去分析英雄列表頁,可是請求到html裏面,並無英雄列表,在英雄列表的節點上,只有「正在加載中」這樣的字樣;一樣的方法,分析英雄詳情也是這種狀況,因此我猜想,這些數據應該是Javascript負責加載的。python
而後我就查看了英雄列表的源代碼,查看外部引入的js文件,以及行內的js腳本,大概在368行,發現了有處理英雄列表的js註釋,而後繼續往下讀這些代碼,發現了第一個彩蛋,也就是他引入了一個champion.js的文件,我猜想,這個應該就是英雄列表大全了,而後我打開了這個連接的js,一眼看過去,黑麻麻一片,而後格式化了一下壓縮的js,肯定這就是英雄列表的js數據文件了。git
前面經過查看列表的源代碼,找到了英雄列表的js數據文件,那麼,我繼續隨機點開了一個英雄的詳情,而後查看英雄詳情源代碼,而後大概在568行看到有一個showSkin的js方法,經過這裏,發現了第二個彩蛋,也就是皮膚圖片的URL地址拼接方法。github
上面找到了皮膚圖片URL的拼接方法,而且發現了一行很關鍵的代碼var skin =LOLherojs.champion[heroid].data.skins
,也就是,這個skin變量,就是英雄皮膚的全部圖片數組,可是這個文件內,並無LOLherojs這個變量,也就是外部引入的,因此,須要繼續查看下面的源代碼,找到引入這個變量的位置,果不其然,在757行,發現了最後一個彩蛋,也就是,英雄皮膚的js文件,經過這裏能夠知道,每一個英雄都有一個單獨的js文件,而且知道了這個js文件的URL拼接方法。web
經過上面的分析,咱們就獲得了爬取LOL皮膚圖片的全部數據準備了,也就是,直接,只須要提取js中的英雄列表以及英雄詳情數據,就可實現咱們的需求了。下面是運行後抓取到的圖片……json
Python運行環境:python3.6
用到的模塊:requests、json、urllib、os
未安裝的模塊,請使用pip instatll進行安裝,例如:pip install requests數組
其餘啥的廢話就很少說了,直接上完整代碼,有問題,直接留言給我就行,另外,代碼已上傳GitHub。再說明一下,那些有問題的英雄詳情的js文件,你們有時間也能夠琢磨下,或者有其餘的更加快捷的爬取這些圖片的方法,也能夠拿出來交流和討論,謝謝。bash
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" 抓取英雄聯盟英雄全皮膚 author: gxcuizy date: 2018-11-13 """
import requests
import json
from urllib import parse
import os
class GetLolSkin(object):
"""抓取LOL英雄皮膚"""
def __init__(self):
"""初始化變量"""
self.hero_url = 'https://lol.qq.com/biz/hero/champion.js'
self.hero_detail_url = 'http://lol.qq.com/biz/hero/'
self.skin_folder = 'skin'
self.skin_url = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big'
@staticmethod
def get_html(url):
"""下載html"""
request = requests.get(url)
request.encoding = 'gbk'
if request.status_code == 200:
return request.text
else:
return "{}"
def get_hero_list(self):
"""獲取英雄的完整信息列表"""
hero_js = self.get_html(self.hero_url)
# 刪除左右的多餘信息,獲得json數據
out_left = "if(!LOLherojs)var LOLherojs={};LOLherojs.champion="
out_right = ';'
hero_list = hero_js.replace(out_left, '').rstrip(out_right)
return json.loads(hero_list)
def get_hero_info(self, hero_id):
"""獲取英雄的詳細信息"""
# 獲取js詳情
detail_url = parse.urljoin(self.hero_detail_url, hero_id + '.js')
detail_js = self.get_html(detail_url)
# 刪除左右的多餘信息,獲得json數據
out_left = "if(!herojs)var herojs={champion:{}};herojs['champion'][%s]=" % hero_id
out_right = ';'
hero_info = detail_js.replace(out_left, '').rstrip(out_right)
return json.loads(hero_info)
def download_skin_list(self, skin_list, hero_name):
"""下載皮膚列表"""
# 循環下載皮膚
for skin_info in skin_list:
# 拼接圖片名字
if skin_info['name'] == 'default':
skin_name = '默認皮膚'
else:
if ' ' in skin_info['name']:
name_info = skin_info['name'].split(' ')
skin_name = name_info[0]
else:
skin_name = skin_info['name']
hero_skin_name = hero_name + '-' + skin_name + '.jpg'
self.download_skin(skin_info['id'], hero_skin_name)
def download_skin(self, skin_id, skin_name):
"""下載皮膚圖片"""
# 下載圖片
img_url = self.skin_url + skin_id + '.jpg'
request = requests.get(img_url)
if request.status_code == 200:
print('downloading……%s' % skin_name)
img_path = os.path.join(self.skin_folder, skin_name)
with open(img_path, 'wb') as img:
img.write(request.content)
else:
print('img error!')
def make_folder(self):
"""初始化,建立圖片文件夾"""
if not os.path.exists(self.skin_folder):
os.mkdir(self.skin_folder)
def run(self):
# 獲取英雄列表信息
hero_json = self.get_hero_list()
hero_keys = hero_json['keys']
# 循環遍歷英雄
for hero_id, hero_code in hero_keys.items():
hero_name = hero_json['data'][hero_code]['name']
hero_info = self.get_hero_info(hero_id)
if hero_info:
skin_list = hero_info['result'][hero_id]['skins']
# 下載皮膚
self.download_skin_list(skin_list, hero_name)
else:
print('英雄【%s】的皮膚獲取有問題……' % hero_name)
# 程序執行入口
if __name__ == '__main__':
lol = GetLolSkin()
# 建立圖片存儲文件
lol.make_folder()
# 執行腳本
lol.run()
複製代碼