1. 程式人生 > 其它 >LPL比賽資料視覺化,完成這個專案,用盡了我的所有Python知識

LPL比賽資料視覺化,完成這個專案,用盡了我的所有Python知識

LPL比賽資料視覺化

效果圖

完成這個專案,我感覺我已經被掏空了,我幾乎用盡了我會的所有知識
html+css+javascript+jQuery+python+requests+numpy+mysql+pymysql+json+ajax+flask+echarts
在這個過程中,並不是那麼順利,遇到了很多坑,好在全部都已經解決
在整個頁面全部功能執行成功的那一刻,我感覺幸福極了

"""
當然在學習Python的道路上肯定會困難,沒有好的學習資料,怎麼去學習呢? 
學習Python中有不明白推薦加入交流Q群號:928946953 
群裡有志同道合的小夥伴,互幫互助, 群裡有不錯的視訊學習教程和PDF!
還有大牛解答!
"""


下面我就帶領大家實踐一下,怎麼從無到有

如果覺得涉及的知識太多,實踐起來困難的同學.不要怕,我專門做了一期視訊一分鐘上手此專案點我觀看視訊



需要用到的Python第三方庫:flask,requests,pymysql,numpy


聽說看著原始碼讀文章絕配哦Github


點我直達視覺化頁面

繪製前端頁面

整個頁面可劃分為10個盒子,使用HTML和CSS就可以把最基礎的框架搭建出來,大家都是pink老師的學生,怎麼在頁面中寫盒子我就不多說了,我主要講解一下如何將echarts的圖表插入到頁面中來

圖1

什麼是Echarts

Echarts官方網站
ECharts 是一個使用 JavaScript 實現的開源視覺化庫,涵蓋各行業圖表,滿足各種需求

ECharts 遵循 Apache-2.0 開源協議,免費商用

ECharts 相容當前絕大部分瀏覽器(IE8/9/10/11,Chrome,Firefox,Safari等)及相容多種裝置,可隨時隨地任性展示

第一個 ECharts 例項

第一個 ECharts 例項原始碼

!!!!!!

使用Echarts的前提是你需要掌握HTML和Javascript的知識,畢竟Echarts是基於JS開發
觀察原始碼不難發現,引入了外部檔案[echarts.js] 如果不引入,程式將無法正常執行
基於準備好的div,繫結事件,初始化echarts例項
指定圖表的配置項和資料,即可顯示圖表
大致流程:引入所需檔案,在HTML定義好div盒子,在JS中繫結事件,初始化echarts例項,指定圖表的配置項和資料

專案中的Echarts

1.引入所需檔案

圖2

說明:上面第一個例項將echarts的程式碼寫在了HTML檔案中,而我為了後期維護起來方便,就分開寫了,所以需要引入[js.js]檔案,也就是我把關於echarts的程式碼都寫在了[js.js]檔案中

2.在HTML定義好div盒子

圖3

3.在JS中繫結事件,初始化echarts例項

圖4

4.指定圖表的配置項和資料

程式碼過多,請到原始碼中檢視

Echarts部分小總結

Echarts部分不是很難,直接到Echarts官網例項中找你想要的圖表,然後複製程式碼,修改圖表的配置和資料即可。我知道你肯定要問“程式碼中的一些屬性我根本就不知道怎麼去使用,怎麼辦嘛” 不要方,請到Echarts官網文件檢視

專案中一共用了5種Echarts圖表,使用的方法大同小異,我相信你可以舉一反三

前端的頁面繪製完畢後,你會發現一個問題。資料都寫死的,而比賽資料幾乎每天都在更新。每天去原始碼中修改對應的資料部分,過不了幾天我想你肯定會厭倦。解決的方法肯定是有的,不光只是爬蟲,還要向Echarts中插入資料(肯定不是手動插,而是機器插)。欲知後事如何,請往下看

爬取比賽資料

在講解爬取資料之前,我還是想簡單介紹一下什麼是爬蟲,回答大家對於爬蟲的一些誤解;假定大家都有一定的爬蟲基礎

什麼是爬蟲,爬蟲違法嗎?

資料從何而來

點我檢視官網比賽資料

圖5


這個網站很特別,是一個動態的網站。如果說只是簡單的使用requests獲取頁面的原始碼;雖然可以獲取到資料,但是資料只有當前顯示的一頁。我最開始的想法是使用selenium這個可以操控瀏覽器的第三方庫,進行資料的獲取。程式碼寫完後,獲取資料沒什麼問題,就是速度太慢了,我也利用requests重新寫了爬蟲程式,速度提升非常明顯(selenium用時20s,requests用時2s;兩個程式還包括了將資料寫入資料庫的程式碼)

所有,selenium版本的爬蟲我不會講,主要還是講解requests的版本


現在,我們來到官網,右鍵點選檢查(如果是谷歌瀏覽器,按F12也可以),點選【Network】

圖6


按CTRL+R 重新整理一下
在【name】下方找到【
LOL_MATCH2_MATCH_TEAMRANK_LIST_134_7_8.js】,接著點選【Preview】,你就會看到這麼一個介面

圖7


觀察右邊的資料,是不是就是戰隊的資訊,只不過就是用json包裝起來了而已,利用Python簡單處理一下就能獲取到你想要的資料。這些資料是用介面形式傳輸的,我們就可以直接爬取介面

點選旁邊的【Headers】,複製【Request URL】後面的網址,我們來到Pycharm

圖8

我們列印一下請求的網址

import requests

def get_info(url):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36 LBBROWSER'}
    response = requests.get(url=url,headers=headers)
    return response.text
info = get_info('https://lpl.qq.com/web201612/data/LOL_MATCH2_MATCH_TEAMRANK_LIST_134_7_8.js')
print(info)

Python

輸出結果:

圖9

可以看出所有的戰隊資訊已經獲取成功,可是輸出的內容是一個str(字串)物件,我們需要使用json.loads()函式將str物件轉換為dict(字典)物件。再使用字典和列表的方法就可以將想要的資料提取出來,並且存放到另外一個字典裡面

import requests
import json

def get_info(url):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36 LBBROWSER'}
    response = requests.get(url=url,headers=headers)
    return response.text
info = get_info('https://lpl.qq.com/web201612/data/LOL_MATCH2_MATCH_TEAMRANK_LIST_134_7_8.js')

info = json.loads(info) #將str物件轉換為dict(字典)物件
info_msg = info['msg']  #使用字典裡面的鍵獲取對於的值

#隊名
teamName = [data['sTeamName'] for data in info_msg]
#出場次數
out_count = [data['iAppearancesFrequency'] for data in info_msg]
#勝場
win = [data['iWin'] for data in info_msg]
#敗場
loss = [data['iLoss'] for data in info_msg]
#勝率
win_rate = [int(str((int(data['iWin'])/(int(data['iWin'])+int(data['iLoss'])))*100)[:2]) for data in info_msg]
#總擊殺
kill_sum = [data['iKill'] for data in info_msg]
#總死亡
death_sum = [data['iDeath'] for data in info_msg]
#插眼
placed_eye = [int(float(data['sAveragingWardPlaced']))for data in info_msg]
#排眼
killed_eye = [int(float(data['sAveragingWardKilled']))for data in info_msg]

infos_list = [('隊名',teamName),('出場次數',out_count),('勝場',win),
              ('敗場',loss),('勝率',win_rate),('總擊殺',kill_sum),
              ('總死亡',death_sum),('插眼',placed_eye),('排眼',killed_eye)]
info_dict = {key:value for key,value in infos_list}
print(info_dict)

Python

輸出結果:

圖10


在上面的程式當中,我運用列表推導式,字典推導式,很輕鬆的就拿到了想要資料。如果你還看不懂推導式,你可以到我這篇文章看看Python高階程式設計之列表推導式、字典推導式、集合推導式

其實,列表推導式還有更簡單的寫法,你可以去原始碼當中的【spider_api.py】檔案中,第125行程式碼檢視,117-122行註釋的程式碼就是未優化的程式碼,留個小小的彩蛋,期待你去發現

聰明的你肯定已經發現了,這只是LPL戰隊的資料,那麼隊員和英雄的資料介面在哪裡呢,剛才檢查網頁的時候,也沒有發現.不要方,接著往下看

動態網站,其他資料介面在哪裡

我們回到官方網站,點選【個人資料】

圖11


接著右鍵檢查,找到【
LOL_MATCH2_MATCH_PERSONALRANK_LIST_134_7_8.js】

圖12


獲取資料的方法就和上面的類似了,我相信你可以舉一反三


然而,獲取英雄資料就不是那麼順利了
還是回到官網,點選【英雄資料】
還是右鍵檢查,找到【
LOL_MATCH2_MATCH_HERORANK_LIST_134_7_8.js】

圖13


你會驚奇的發現,為什麼沒有英雄的名字,而只有【iChampionId】和其他資料
於是,我們大膽的猜測,這些【iChampionId】會不會是英雄對應的ID呢?

尋找英雄名稱

想檢視英雄的名稱,我腦袋裡面第一個蹦出了的想法就是英雄聯盟官網
老規矩,右鍵檢查,找到【hero_list.js】,Amazing呀!

圖14


你仔細看,發現英雄名稱前面有個【heroId】,會不會就和我們剛才看到的【iChampionId】相對應呢?
你不用去對比啦,我已經對比過了,就是相對應的,嘿嘿


雖然已經找到英雄名稱,但是新的問題又來了
從兩個介面獲取到的資料,怎麼保證【iChampionId】的英雄匹配到正確的名稱
如何獲取資料,我就不多嘴了,詳細程式碼請檢視原始碼.我這裡主要講解一下如何匹配正確的英雄名稱

name = []
    for i in hero_key_id_top60:
        for j in hero_name_id_list:
            if i == j :
                #由於從lpl資料頁面無法獲取到英雄名稱,只能獲取到對應的id
                #一層迴圈是pick率前60的英雄id,二層是所有英雄的的id
                #通過if判斷,將pick率前60的英雄寫入到指定列表中
                name.append(hero_name_list[hero_name_id_list.index(j)])

Python

【hero_key_id_top60】中的內容:

圖15


【hero_name_id_list】中的內容:

圖16


【hero_name_list】中的內容:

圖17


【name 】中的內容:

圖18

資料已到位,下一步匯入資料庫

資料庫互動

首先,請在你的電腦上面建立一個名為【lpl】的資料庫,不需要建表,後面我會講解如何用pymysql建表

匯入資料

我們需要連線自己的資料庫
程式碼如下,值得注意的是,passwd='你自己資料庫的密碼'
如果說看不懂程式碼,可以先去了解一下MySQL和pyMySQL

import pymysql

def mysql():
    db = pymysql.connect(
        host='localhost', user='root',
        passwd='123456', db='lpl', charset='utf8')
    cur = db.cursor()
    return db,cur

Python

資料庫連線成功後,我們以【戰隊排行榜】為例

db, cur = mysql()
    try:

        # 是否存在這個表,若存在就刪除,【戰隊排行榜前五】為表的名稱
        cur.execute("DROP TABLE IF EXISTS 戰隊排行榜前五")
        # 建立表sql語句
        set_sql_top5 = """                             
                    create table 戰隊排行榜前五(
                    戰隊名稱 varchar(20),
                    出場次數 varchar(10),
                    勝率 varchar(10))
                      """
        # 執行sql語句
        cur.execute(set_sql_top5)
        db.commit() # 儲存

        # 準備寫入資料的sql語句
        save_sql_top5 = "INSERT INTO 戰隊排行榜前五 values(%s,%s,%s);"
        # 寫入資料庫,引數一:寫入的sql語句  引數二:資料,型別為列表,裡面的元素型別是元組
        cur.executemany(save_sql_top5,info_list)
        db.commit()

        print("寫入資料庫成功")
    except Exception as e:
        print("建立資料庫失敗:case%s" % e)

Python

【info_list】當中的資料

圖19

資料庫中的資料

圖20

取出資料

資料庫還是需要連線的,我們任然以【戰隊排行榜】為例

import pymysql

def mysql():
    db = pymysql.connect(
        host='localhost', user='root',
        passwd='123456', db='lpl', charset='utf8')
    cur = db.cursor()
    return db,cur
def query(sql):
    db,cur = mysql()
    cur.execute(sql)    #執行傳入的sql語句
    res =cur.fetchall() #獲取sql語句欄位中的所有資料
    return res

#sql語句,從【戰隊排行榜前五】這張表中,選擇戰隊名稱,出場次數,勝率
sql_wings = 'SELECT 戰隊名稱,出場次數,勝率 FROM 戰隊排行榜前五'

infos_wings = query(sql_wings) #取出資料
#print(infos_wings) : (('TES', '40', '75%'), ('JDG', '43', '72%'), ('V5', '49', '61%'), ('IG', '44', '59%'), ('SN', '52', '59%'))

name = [info[0] for info in infos_wings]
out_count = [info[1] for info in infos_wings]
win_rate = [info[2] for info in infos_wings]
infos_list = [('name', name), ('outcount', out_count), ('winRate', win_rate)]

#為什麼最後要轉換成字典的形式,我會在後面向前端傳輸資料的時候講解
infos_dict = {key: value for key, value in infos_list}
#print(infos_dict)
#{'name': ['TES', 'JDG', 'V5', 'IG', 'SN'], 'outcount': ['40', '43', '49', '44', '52'], 'winRate': ['75%', '72%', '61%', '59%', '59%']}

Python

Web程式開發

什麼是Web程式

Web應用程式是一種可以通過Web訪問的應用程式。Web應用程式的一個最大好處是使用者很容易訪問應用程式。使用者只需要有瀏覽器即可,不需要再安裝其他軟體
能夠開發web程式的程式語言有很多,比如Java,Php,Python等
而我們選擇用Python進行開發,使用Falsk框架進行快速開發

什麼是Falsk

Flask是一個使用 Python編寫的輕量級Web應用框架。其WSGl( Python Web Server Gateway Interface)工具包採用 Werkzeug,模板引擎則使用 Jinja2,是目前十分流行的Web框架
這裡給大家推薦一期視訊,Flask快速入門.由於我的能力有限,還請大家花點時間將視訊看完,再接著往後看文章

使用Flask連線前端頁面

假定大家已經看完了視訊,嘿嘿

使用pycharm建立一個flask專案,會自動幫我們生成兩個資料夾【templates】【static】和一個python檔案【app.py】
我們需要將寫好的HTML檔案放在【templates】目錄下,CSS、JS和所用到的圖片放在【static】目錄下,如下圖所示

圖21

值得注意的是,也是一個坑,HTML檔案當中,引用的外部檔案,檔案地址一定要去修改。因為我們是先寫好的前端頁面,而flask當中需要我們將外部檔案都放在【static】當中

注意事項

引入模板

這裡所說的模板,就是我們寫好的HTMl檔案,只不過需要使用render_template()將其引入

import lpldata
from flask import Flask,render_template

app = Flask(__name__)
LPL = lpldata.Lpl_Data()#從資料庫獲取資料

@app.route('/')#預設路由
def hello_world():
    return render_template("index.html")#引入模板

Python

使用Ajax傳輸資料

什麼是Ajax

Ajax是Asynchronous Javascript and XML的簡稱,通過Ajax向伺服器傳送請求,接收伺服器返回的json資料,然後使用 Javascript修改網頁,來實現頁面區域性資料更新。使用 Jquery框架可方便的編寫Ajax程式碼,需要 Jquery.js檔案

基本格式

$.ajax({
    type:"post",     //請求型別
    url:"/目標路由",  //請求地址
    data:{},         //資料
    datatype:"json",
    success:function (data) {
        //請求成功的回撥函式,data是返回的資料
    },
    error:function () {
        //請求失敗時執行
    }
})

JavaScript

我們先到app.py檔案中,定義好一個路由(/wingsvd),methods新增一個'post',這裡以【戰隊勝負圖表】為例

@app.route('/wingsvd',methods=['GET','POST'])
def wings_vd():
    return LPL.get_wings_vd()

Python

LPL.get_wings_vd(),你可以到lpldata.py檔案檢視相關的程式碼。主要功能就是從資料獲取資料,並且將資料整理好後,存到字典裡面,最後使用json.dumps()將dict(字典)物件轉換為json物件,最為函式的返回值返回

現在回到Ajax的部分,你可以到【js.js】檔案中359行檢視

function echarts_4() {
    // 基於準備好的dom,初始化echarts例項
    var myChart = echarts.init(document.getElementById('echart4'));
    var lpl = {};
    $.ajax({
        url:'/wingsvd', //這裡的地址是不是很眼熟,沒錯就是剛才定義的路由地址
        data: {},
        type: 'POST',
        async: false,
        dataType:'json',
        success: function (data) {
            lpl.name = data.name;  // 使用json的方法,提取剛才LPL.get_wings_vd()返回的資料
            lpl.victory = data.victory;
            lpl.defeat = data.defeat;
            lpl.winRate = data.winRate;
......

JavaScript

資料提取成功後,就可以在後面的echarts程式碼中修改對應的配置,圖表就可以顯示出資料啦

這裡以圖表的X軸為例

xAxis: [
           {
                type: "category",
                data: lpl.name,  //上面的程式碼是不是也有它呀,有就對啦
                axisLine: { lineStyle: {color: "rgba(255,255,255,.1)"}},
                axisLabel:  { textStyle: {color: "rgb(255,255,255)", fontSize: '16', }},
            },
       ],

JavaScript

所有的圖表傳輸資料的操作方法都是一樣的,先在【app.py】中建立路由,返回你需要的資料,再到【js.js】當中寫Ajax和Echarts的程式碼

最後的勝利

所有的準備工作完成後,我們就只剩最後一步啦!

if __name__ == '__main__':
    app.run(debug=True)

Python

右鍵,執行,點選下方的地址,視覺化的頁面就呈現在了你的眼前

圖24