爬取LOL官网所有英雄皮肤

爬取LOL官网所有英雄皮肤_第1张图片最近在写爬虫,基本的请求库、解析库也复习了一遍。我这个人比较喜欢造轮子,不喜欢黑盒子,爬虫还是喜欢用基本的库一点一点写,这样虽然复杂了一点,但是有了掌控感。
闲来无事,找个事情做一做,就写个爬虫爬一下LOL官网上英雄的皮肤玩玩,也算是纪念曾经玩LOL的生涯。

规划设想

打开英雄总览的网页,所有的英雄都在这里了。首先想到的是从这个页面拿到各个英雄的子页面,在子页面提取到皮肤图片的链接,下载图片完工。
爬取LOL官网所有英雄皮肤_第2张图片
爬取LOL官网所有英雄皮肤_第3张图片

开始行动

就参照这个思路开始做吧!

  1. 拿到所有子页面链接。
  2. 从子页面链接找到皮肤图片url,返回所有url和图片名字。
  3. 下载图片。

首先在主页面看了一下网页源码,没有找到各个英雄的信息。比如暗裔剑魔亚托克斯Aatrox这些全都找不到。

主页面只是个空壳,没有有用信息

不过找到了一个js函数,发现了构造英雄子页面链接的一些端倪:
爬取LOL官网所有英雄皮肤_第4张图片
因为各个英雄的链接只有id不同,其实也就是英雄的英文名字,现在我只需要拿到英雄的id就好了。那么从哪里找这些id呢?

随后我在开发者工具中搜索剑魔的idAatrox,发现一个名为champion.js的文件中有所有英雄的,而且有用信息是json格式,这就比较方便了。于是构造请求,拿到这个js的信息:

英雄的id都在champion.js

爬取LOL官网所有英雄皮肤_第5张图片

def getHeroDetail(this)->None:
    url = 'https://lol.qq.com/biz/hero/champion.js'
    r = requests.get(url = url, headers = this.headers)
    rawContent = r.content.decode('utf-8')
    this.herosDetail = json.loads(rawContent[50:-1])

现在已经有了各个英雄的id,可以构造出来子页面的链接了。可是到子页面一看,网页源码里面依旧没有皮肤图片的链接。

子页面也是个空壳
构造皮肤图片需要找到ids编号

不过我又找到了一个跟显示图片有关的js函数:

爬取LOL官网所有英雄皮肤_第6张图片
原来所有图片对应的url只有ids不同。在这里插入图片描述
不过到哪里找这个ids呢?我又从开发者工具中搜索剑魔的默认皮肤图片的ids266000,找到了一个js。我把这个js复制到本地研究了一下,发现里面含有剑魔的所有皮肤对应的ids。而且这个js是以英雄的id命名的。

ids编号在英雄id.js

刚才已经拿到了所有英雄的id,那么就可以拿到所有英雄的这个js文件了,只需要从这个js里拿到ids就可以构造出皮肤图片的url。那么这样的话,英雄子页面的链接就没什么用了!
爬取LOL官网所有英雄皮肤_第7张图片

def getSkins(this)->list:
    '''
    返回皮肤的url,以及皮肤的名字。
    第一级元素是英雄级别
    第二级元素是单个英雄的皮肤级别
    第三级元素是皮肤url和皮肤名字。比如:(url, 腥红之月 亚托克斯)
    '''
    skinBaseUrl = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big'
    skins = []
    for title in this.herosDetail['keys'].values():
        jsUrl = 'https://lol.qq.com/biz/hero/'+title+'.js'
        r = requests.get(jsUrl, this.headers)
        rawContent = r.content.decode('utf-8')
        hero = json.loads(re.search('(.*?\=){2}(\{.*\})', rawContent).group(2))
        skins.append([(skinBaseUrl+i['id']+'.jpg', i['name'] if i['name'] != 'default' else this.herosDetail['data'][title]['name']) for i in hero['data']['skins']])
    return skins

保存图片要注意文件名不能有/符号

已经拿到了皮肤的url和皮肤名字,随后就是皮肤图片的保存了:

def saveSkins(this):
    for aHero in this.getSkins():
        for skinUrl, name in aHero:
            try:
                name = re.sub('/', '/', name)#文件名中不能有`/`符号,要把半角替换为全角
                r = requests.get(skinUrl, this.headers)
                with open(name+'.jpg', 'wb') as f:
                    f.write(r.content)
                print('Saved', name)
            except(KeyboardInterrupt):
                sys.exit(0)
            except:
                print('Filed to save', name)

再定义一个启动函数:

def run(this):
    this.getHeroDetail()
    this.saveSkins()

开启主函数

if __name__ == '__main__':
    spider = LOLSpider()
    spider.run()

到这里已经写完了所有的代码。贴一下完整的代码:

#============================================================
# Create Time:  		2019-07-15 22:48:33
# Writer:				Wenhao	[email protected]
# File Name:			LOLSpider.py
# File Type:			PY Source File
# Tool:					Mac -- vim & python
# Information:  		爬取LOL官网上的所有英雄皮肤,存到当前文件夹中
#============================================================
#coding=utf-8
import requests
import json
import re
import sys

class LOLSpider():
    headers = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'}
    def getHeroDetail(this)->None:
        url = 'https://lol.qq.com/biz/hero/champion.js'
        r = requests.get(url = url, headers = this.headers)
        rawContent = r.content.decode('utf-8')
        this.herosDetail = json.loads(rawContent[50:-1])

    def getSkins(this)->list:
        '''
        返回皮肤的url,以及皮肤的名字
        第一级元素是英雄级别
        第二级元素是单个英雄的皮肤级别
        第三级元素是皮肤url和皮肤名字。比如:(url, 腥红之月 亚托克斯)
        '''
        skinBaseUrl = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big'
        skins = []
        for title in this.herosDetail['keys'].values():
            jsUrl = 'https://lol.qq.com/biz/hero/'+title+'.js'
            r = requests.get(jsUrl, this.headers)
            rawContent = r.content.decode('utf-8')
            hero = json.loads(re.search('(.*?\=){2}(\{.*\})', rawContent).group(2))
            skins.append([(skinBaseUrl+i['id']+'.jpg', i['name'] if i['name'] != 'default' else this.herosDetail['data'][title]['name']) for i in hero['data']['skins']])
        return skins

    def saveSkins(this):
        for aHero in this.getSkins():
            for skinUrl, name in aHero:
                try:
                    name = re.sub('/', '/', name)#文件名中不能有`/`符号,要把半角替换为全角
                    r = requests.get(skinUrl, this.headers)
                    with open(name+'.jpg', 'wb') as f:
                        f.write(r.content)
                    print('Saved', name)
                except(KeyboardInterrupt):
                    sys.exit(0)
                except:
                    print('Filed to save', name)

    def run(this):
        this.getHeroDetail()
        this.saveSkins()

if __name__ == '__main__':
    spider = LOLSpider()
    spider.run()

总结

这个爬虫写的还算顺利,虽然中间也经历了一些曲折,并没有按照自己最初设想的步骤完成,也算是在尝试中达到了目的。要注意有用的信息在js里面,主页面都是一个空壳,要想拿到信息还得去找到信息所在的请求。
爬取LOL官网所有英雄皮肤_第8张图片

你可能感兴趣的:(爬虫)