前文
本文主要分為兩個部分
- 一部分是爬蟲,這邊是選擇爬取英雄聯盟官網英雄資料中的英雄皮膚圖片,如下為新英雄seraphine的頁面,包含英雄對應的所有皮膚;

- 另一部分是圖片的合成,先將所有英雄皮膚圖片拼接成為一張圖作為背景,然后與另一張圖片進行合成,效果如下:

爬蟲
思路整理
- F12打開控制臺后重繪頁面(https://lol.qq.com/data/info-defail.shtml?id=147),既然是找圖片,直接在img標簽下找就好了;

- 獲取到圖片的地址之后(https://game.gtimg.cn/images/lol/act/img/skin/big147001.jpg),接著再往下找,在xhr標簽下,找到了包含皮膚圖片地址的介面(https://game.gtimg.cn/images/lol/act/img/js/hero/147.js),測驗一下,可以直接訪問,沒啥限制;

- 多看幾個英雄的頁面就能發現,這個147其實就是對應英雄的ID,如果我們有英雄的ID,直接拼接成新的介面地址就可以,接著繼續往下找能獲取英雄ID的介面;
- 在資料庫首頁重繪,有個叫hero_list(https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js)的就很明顯,從回傳的內容來看,確實包含了我們需要的英雄ID;

- 這樣思路就很清晰了,先從hero_list獲取所有英雄的ID,然后拼接成單個英雄資訊的介面訪問獲取到皮膚圖片的地址,下載圖片完事~
完整代碼
為了速度快點,加了一個異步,實測6S爬取完所有的皮膚~

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : AwesomeTang
# @File : crawler.py
# @Version : Python 3.7
# @Time : 2020-11-06 23:05
import requests
import asyncio
import os
from aiohttp import ClientSession
import aiohttp
import json
from datetime import datetime
async def skins_downloader(semaphore, hero_id, hero_name):
async with semaphore:
url = 'https://game.gtimg.cn/images/lol/act/img/js/hero/{}.js'.format(hero_id)
dir_name = 'skins/{}'.format(hero_name)
if not os.path.exists(dir_name):
os.mkdir(dir_name)
async with ClientSession(connector=aiohttp.TCPConnector(ssl=False)) as session:
async with session.get(url) as response:
response = await response.read()
for skin in json.loads(response)['skins']:
if skin['mainImg']:
img_url = skin['mainImg']
# kda女團皮膚名帶斜杠,replace掉
path = os.path.join(dir_name, '{}.jpg'.format(skin['name'].replace('/', ''), ))
async with session.get(img_url) as skin_response:
with open(path, 'wb') as f:
print('\rDownloading [{:^10}] {:<20}'.format(hero_name, skin['name']), end='')
f.write(await skin_response.read())
def hero_list():
return requests.get('https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js').json()['hero']
async def run():
semaphore = asyncio.Semaphore(30)
heroes = hero_list()
tasks = []
for hero in heroes:
tasks.append(asyncio.ensure_future(skins_downloader(semaphore, hero['heroId'], hero['title'])))
await asyncio.wait(tasks)
if __name__ == '__main__':
start_time = datetime.now()
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
loop.close()
end_time = datetime.now()
time_diff = (end_time - start_time).seconds
print('\nTime cost: {}s'.format(time_diff))
每個英雄對應一個檔案夾~

圖片合成
圖片尺寸處理
- 因為最后圖片合成需要保持一樣的尺寸,所以第一步我們先把主圖的尺寸resize成我們想要的;
- 英雄皮膚的圖片都是980*500,我們把皮膚圖片尺寸縮小10倍也就是98*50,然后保證每行有50張子圖,這樣便得到了我們需要resize的寬度(98*50),然后根據主圖本身的長寬比計算出我們需要resize的高度,具體代碼如下:
mask_img = Image.open('/home/kesci/work/skins/league of legend.jpeg')
# 獲取圖片本身寬度、高度
width, height = mask_img.size
# 計算resize后的尺寸,注意取整
to_width = 98 * 50
to_height = ((to_width / width) * height // 50) * 50
mask_img = mask_img.resize((int(to_width), int(to_height)), Image.ANTIALIAS)
# 顯示圖片
plt.figure(figsize=(25,15))
plt.imshow(mask_img)
plt.axis('off')
plt.show()

子圖拼接
- 接下來便是把英雄圖片拼接成一張圖片,尺寸與之前主圖尺寸保持一致;
- 讀取所有皮膚圖片將尺寸resize為98*50,轉為
np.array格式快取到list中共后面呼叫;
skin_array_collection = []
for fpath, dirname, fnames in os.walk('/home/kesci/work/skins'):
if not dirname:
for fn in fnames:
try:
skin_array_collection.append(np.array(Image.open(os.path.join(fpath, fn)).convert('RGB').resize((98, 50), Image.ANTIALIAS)))
except OSError:
print('讀取檔案出錯:「{}」'.format(os.path.join(fpath, fn)))
- 將剛剛的
array隨機組合到一起,轉為圖片就好了~
w_times, h_times = int(to_width / 98), int(to_height / 50)
bg_img = np.zeros_like(np.array(mask_img))
for i in tqdm(range(w_times), desc='MERGE'):
for j in range(h_times):
bg_img[j * 50:(j + 1) * 50, i * 98:(i + 1) * 98, :] = random.choice(skin_array_collection)
bg_img = Image.fromarray(bg_img)
# 顯示圖片
plt.figure(figsize=(25,15))
plt.imshow(bg_img)
plt.axis('off')
plt.show()

圖片合成
- 這邊使用了Pillow中的
Image.blend,將主圖和剛才生成的皮膚背景圖合成到一起,通過alpha引數控制背景的透明程度;
img = Image.blend(bg_img, mask_img, alpha=0.8)
img.save('/home/kesci/work/skins/out_put.jpeg')
# 顯示圖片
plt.figure(figsize=(25,15))
plt.imshow(img)
plt.axis('off')
plt.show()
- 效果如下:


轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/209719.html
標籤:python
上一篇:零基礎學Docker【2】 | 一文帶你快速學習Docker常用命令
下一篇:cgb2007-京淘day09
