Python3爬取英雄聯盟英雄皮膚大圖

前言

之前一直想爬取LOL英雄皮膚的高清圖片,最近有事,也沒怎麼去研究,所以,現在纔去看了下,並且寫了Python腳本來抓取皮膚圖片。需要說明一下,這個腳本有部分英雄沒有抓取到,但是具體原因,我目前還沒搞懂,我是相當納悶的。大家有興趣的,可以看看後面遺留問題,一起研究下。

 

爬蟲思路

初步嘗試

我先查看了network,並沒有發現有可用的API;然後又用bs4去分析英雄列表頁,但是請求到html裏面,並沒有英雄列表,在英雄列表的節點上,只有“正在加載中”這樣的字樣;同樣的方法,分析英雄詳情也是這種情況,所以我猜測,這些數據應該是Javascript負責加載的。

繼續嘗試

然後我就查看了英雄列表的源代碼,查看外部引入的js文件,以及行內的js腳本,大概在368行,發現了有處理英雄列表的js註釋,然後繼續往下讀這些代碼,發現了第一個彩蛋,也就是他引入了一個champion.js的文件,我猜測,這個應該就是英雄列表大全了,然後我打開了這個鏈接的js,一眼看過去,黑麻麻一片,然後格式化了一下壓縮的js,確定這就是英雄列表的js數據文件了。

接着嘗試

前面通過查看列表的源代碼,找到了英雄列表的js數據文件,那麼,我繼續隨機點開了一個英雄的詳情,然後查看英雄詳情源代碼,然後大概在568行看到有一個showSkin的js方法,通過這裏,發現了第二個彩蛋,也就是皮膚圖片的URL地址拼接方法。

最後嘗試

上面找到了皮膚圖片URL的拼接方法,並且發現了一行很關鍵的代碼var skin =LOLherojs.champion[heroid].data.skins,也就是,這個skin變量,就是英雄皮膚的所有圖片數組,但是這個文件內,並沒有LOLherojs這個變量,也就是外部引入的,所以,需要繼續查看下面的源代碼,找到引入這個變量的位置,果不其然,在757行,發現了最後一個彩蛋,也就是,英雄皮膚的js文件,通過這裏可以知道,每個英雄都有一個單獨的js文件,並且知道了這個js文件的URL拼接方法。

思路總結

通過上面的分析,我們就得到了爬取LOL皮膚圖片的所有數據準備了,也就是,直接,只需要提取js中的英雄列表以及英雄詳情數據,就可實現我們的需求了。下面是運行後抓取到的圖片……

運行環境

Python運行環境:python3.6

用到的模塊:requests、json、urllib、os

未安裝的模塊,請使用pip instatll進行安裝,例如:pip install requests

完整代碼

其他啥的廢話就不多說了,直接上完整代碼。再說明一下,那些有問題的英雄詳情的js文件,大家有時間也可以琢磨下,或者有其他的更加快捷的爬取這些圖片的方法,也可以拿出來交流和討論,謝謝。

#!/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()


公衆號:Python大咖那些事

關注領取更多資料,每日更新Python相關技術文!

Python開發學習交流羣:705673780,一起學習交流哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章