• 【python】王者荣耀全英雄高清壁纸爬虫共467M(多线程)



    1. 成果展示

    在这里插入图片描述

    2. 单张预览

    在这里插入图片描述

    3. 软件下载

    win64:https://ghgxj.lanzous.com/iCfeUj9vhij

    win32maclinux用户请自行通过源码打包。

    4. 壁纸下载

    共467M:https://ghgxj.lanzous.com/b08xsj0va

    5. 进度打印

    壁纸分辨率及序号如下:
    1 > 缩略图
    2 > 1024x768
    3 > 1280x720
    4 > 1280x1024
    5 > 1440x900
    6 > 1920x1080 (推荐)
    7 > 1920x1200
    8 > 1920x1440
    请选择分辨率 (默认是6):
    457/457 |████████████████████| 任务进度: 100% 已用时间: 89S 剩余时间: 0S
    请按任意键继续. . .
    

    6. 目标网址

    https://pvp.qq.com/web201605/wallpaper.shtml

    7. 依赖模块

    pip install requests
    

    8. 完整代码

    # run.py
    import re, os, time, json, requests
    from urllib.parse import unquote
    import concurrent.futures as cf
    
    
    class WangzheDownloader(object):
        # 初始化
        def __init__(self):
            self.root = './heros/'
            if not os.path.exists(self.root):
                os.mkdir(self.root)
            self.numberSize = 6
            self.url = 'https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page={}&iOrder=0&SearchKey=sProdName&iSortNumClose=1&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1607443031450'
            res = requests.get(self.url.format(0)).json()
            self.totalPage = int(res.get('iTotalPages'))
            self.sum = int(res.get('iTotalLines'))
            self.count = 0
            self.startTime = time.time()
    
        # 选择壁纸分辨率
        def size(self):
            print('壁纸分辨率及序号如下: ')
            size_list = [
                '1 > 缩略图',
                '2 > 1024x768',
                '3 > 1280x720',
                '4 > 1280x1024',
                '5 > 1440x900',
                '6 > 1920x1080 (推荐)',
                '7 > 1920x1200',
                '8 > 1920x1440'
            ]
            for size in size_list:
                print(size)
            numberSize = input('请选择分辨率 (默认是6): ')
            self.numberSize = numberSize if numberSize else 6
    
        # 获取103位英雄的名字
        def name(self):
            url = 'https://pvp.qq.com/web201605/js/herolist.json'
            res = requests.get(url).json()
            self.hero = [item['cname'] for item in res]
    
        # 单张图片下载
        def down(self, img_name, img_url):
            res = requests.get(img_url)
            with open(img_name, 'wb') as f:
                f.write(res.content)
            self.count += 1
            endTime = time.time()
            self.show(self.count, self.sum, endTime-self.startTime)
    
        # 爬取每一页
        def page(self, numberPage):
            res = requests.get(self.url.format(numberPage)).json()
            for item in res.get('List'):
                # 去除图片名中的特殊字符
                img_name = re.sub('[/\:*?"<>|]', '', unquote(item['sProdName']))
    
                # 根据英雄名建立分类文件夹
                temp = re.split('[·-]', img_name)
                control = True
                for each in temp:
                    if each in self.hero:
                        control = False
                        img_dir = self.root+each
                        if not os.path.exists(img_dir):
                            os.mkdir(img_dir)
                        img_name = img_dir+'/'+img_name+'.jpg'
                        break
                if control:
                    img_dir = self.root+'其它'
                    if not os.path.exists(img_dir):
                        os.mkdir(img_dir)
                    img_name = img_dir+'/'+img_name+'.jpg'
                
                img_url = unquote(item[f'sProdImgNo_{self.numberSize}'])
                img_url = img_url.replace('/200', '/0') # /0才是原图,/200都是缩略图
                self.down(img_name, img_url)
    
        # 打印进度条
        def show(self, num, _sum,  runTime):
            barLen = 20  # 进度条的长度
            perFin = num/_sum
            numFin = round(barLen*perFin)
            numNon = barLen-numFin
            leftTime = (1-perFin)*(runTime/perFin)
            print(
                f"{num:0>{len(str(_sum))}}/{_sum}",
                f"|{'█'*numFin}{' '*numNon}|",
                f"任务进度: {perFin*100:.0f}%",
                f"已用时间: {runTime:.0f}S",
                f"剩余时间: {leftTime:.0f}S",
                end='
    '
            )
            if num == _sum:
                print()
    
        # 多线程
        def main(self):
            self.size()
            self.name()
            with cf.ThreadPoolExecutor() as tp:
                for page in range(self.totalPage):
                    tp.submit(self.page, page)
    
    
    if __name__ == "__main__":
        WangzheDownloader().main()
    

    9. 代码剖析

    打开目标网址,通过F12检查发现,有现有的API接口可供调用:
    在这里插入图片描述
    API接口里面存的就是壁纸的下载直链,也提供了图片总张数和总页数的信息:
    在这里插入图片描述
    既然有接口,我们就直接请求接口了,请求url如下:

    https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=0&iOrder=0&SearchKey=sProdName&iSortNumClose=1&jsoncallback=jQuery17107126052728750412_1607442410515&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1607443031450
    

    jsoncallback=jQuery17107126052728750412_1607442410515这个参数不要,不然返回的是带前缀和后缀的jsonp数据,会影响解析。

    API接口返回的json数据中,List存的是图片列表,列表长度就是请求参数中的iListNum的值,默认是20,也就是每页返回20张壁纸。

    每张壁纸又有8url,从sProdImgNo_1sProdImgNo_8,对应于8种分辨率:
    在这里插入图片描述
    分辨率的对应关系如下:

    size_list = [
        '1 > 缩略图',
        '2 > 1024x768',
        '3 > 1280x720',
        '4 > 1280x1024',
        '5 > 1440x900',
        '6 > 1920x1080 (推荐)',
        '7 > 1920x1200',
        '8 > 1920x1440'
    ]
    

    你可能会问:不是还有一个sThumbURL吗?其实这个就是sProdImgNo_1,不信你可以试试。

    sProdName是图片名字,无论是图片名还是链接,都需要进行url解码,在python中通过unquote解码:

    from urllib.parse import unquote
    

    解码后,把图片链接在浏览器中打开,你会发现:怎么都是缩略图?这个将图片链接后面的/200改为/0就行了。

    img_url = img_url.replace('/200', '/0') # /0才是原图,/200都是缩略图
    

    最后要说的就是图片分类问题了,每个英雄都有很多皮肤,所以我们根据英雄名建立文件夹,将同一英雄的不同皮肤都放到同一文件夹。

    王者荣耀英雄名也是找了一个API接口获取的,获取方式如下:

    def name(self):
        url = 'https://pvp.qq.com/web201605/js/herolist.json'
        res = requests.get(url).json()
        self.hero = [item['cname'] for item in res]
    

    至于这个获取英雄名的接口,也是通过F12检查英雄资料找到的:
    在这里插入图片描述
    接口响应信息如下,直接在浏览器中预览会乱码:
    在这里插入图片描述
    json文件下载下来查看,是正常的,其中cname就是英雄名:
    在这里插入图片描述

    10. 打包教程

    10.1. 打包前的准备

    先安装pipenv,在pipenv创建的虚拟环境下打包,这样打包的软件会很小。

    pip install pipenv
    

    10.2. 具体打包流程

    1. 打开cmd控制台
    2. cd到项目路径
    3. 创建虚拟环境:pipenv install
    4. 打开虚拟环境:pipenv shell
    5. 安装依赖模块:pip install requests
    6. 安装打包工具:pip install pyinstaller
    7. 执行打包命令:pyinstaller -F -i favicon.ico run.py

    10.3. 需要注意的点

    run.py就是上方的完整代码favicon.ico是软件图标,我用的是下面这个:
    在这里插入图片描述
    下载下来是png格式,你必须转为ico格式,这里推荐一个在线转换的工具:

    png2ico:https://www.easyicon.net/covert/

    11. 相关推荐

    【python】王者荣耀全英雄头像爬虫(多线程)

  • 相关阅读:
    Java内存模型原理,你真的理解吗?
    CentOS 7.4 下搭建 Elasticsearch 6.3 搜索群集
    CentOS 7下ElasticSearch集群搭建案例
    分布式系统理论基础
    分布式系统理论进阶
    Paxos,Raft,Zab一致性协议-Raft篇
    P2P 网络核心技术:Gossip 协议
    分布式系统Paxos算法
    Hacker News的热门排名算法(转)
    Elasticsearch分布式机制和document分析
  • 原文地址:https://www.cnblogs.com/ghgxj/p/14219064.html
Copyright © 2020-2023  润新知