• 爬取英雄联盟所有皮肤图片实现千图成像~


    前文

    本文主要分为两个部分

    • 一部分是爬虫,这边是选择爬取英雄联盟官网英雄资料中的英雄皮肤图片,如下为新英雄seraphine的页面,包含英雄对应的所有皮肤;

    • 另一部分是图片的合成,先将所有英雄皮肤图片拼接成为一张图作为背景,然后与另一张图片进行合成,效果如下:

    爬虫

    思路整理

    1. F12打开控制台后刷新页面(https://lol.qq.com/data/info-defail.shtml?id=147),既然是找图片,直接在img标签下找就好了;

    2. 获取到图片的地址之后(https://game.gtimg.cn/images/lol/act/img/skin/big147001.jpg),接着再往下找,在xhr标签下,找到了包含皮肤图片地址的接口(https://game.gtimg.cn/images/lol/act/img/js/hero/147.js),测试一下,可以直接访问,没啥限制;

    3. 多看几个英雄的页面就能发现,这个147其实就是对应英雄的ID,如果我们有英雄的ID,直接拼接成新的接口地址就可以,接着继续往下找能获取英雄ID的接口;

    4. 在资料库首页刷新,有个叫hero_list(https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js)的就很明显,从返回的内容来看,确实包含了我们需要的英雄ID;

    5. 这样思路就很清晰了,先从hero_list获取所有英雄的ID,然后拼接成单个英雄信息的接口访问获取到皮肤图片的地址,下载图片完事~

    完整代码

    为了速度快点,加了一个异步,实测6S爬取完所有的皮肤~

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Author  : 李运辰
    # @File    : crawler.py
    # @Version : Python 3.7
    # @Time    : 2020-11-30 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('
    Downloading [{:^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('
    Time 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()
    
    
    
    • 效果如下:

    - END -

    各种爬虫源码获取方式

    识别文末二维码,回复:爬虫源码

    欢迎关注公众号:Python爬虫数据分析挖掘,方便及时阅读最新文章

    记录学习python的点点滴滴;

    回复【开源源码】免费获取更多开源项目源码;

  • 相关阅读:
    懂一点Python系列——快速入门
    DatagridView 控件列顺序与设置的不一样
    WinForm Column cannot be added because its CellType property is null.
    Rabbitmq消息服务器通讯异常: name must not be blank
    Redis 数据库
    redis 安装与使用
    windows 服务的安装与卸载之bat脚本命令
    以超级管理员方式运行bat文件
    CMD 下切换目录
    C#导出Excel后关闭进程EXCEL.EXE
  • 原文地址:https://www.cnblogs.com/chenlove/p/14088513.html
Copyright © 2020-2023  润新知