一、選題的背景
NBA受到世界各地極大多數人的喜愛,不分年齡,學生、員工、勞動工人等社會各界都有熱愛籃球的人,也有各自喜歡信仰的球星,在NBA中國官方網站里他們更好的了解和清楚自己喜愛的球星和其它聯盟里的球星的一些數據對比,知道他們近期的一些起伏和爆發,本次爬蟲建立在這基礎上,通過對網頁數據的提取並進行可視化對比,更好地了解聯盟里球員的排名和其余各項數據之間的關系來分析對球隊的貢獻好與壞。
二、設計方案
1.爬蟲名稱:爬取NBA球員排名及各項數據
2.爬取內容:爬取NBA球員排名、場均得分、各項命中率等
3.方案概述:訪問網頁得到狀態碼200,分析網頁源代碼,找出所需要的的標簽,逐個提取標簽保存到相同路徑csv文件中,讀取該文件,進行數據清洗,數據模型分析,數據可視化處理,繪制排名與其余幾項數據的關系圖。
技術難點:
1.在爬取網頁數據,提取數據成csv文件時,由於數據較為雜亂。
2. 做數據分析,即求回歸系數,因為標題是文字,無法與數字作比較,需要把標題這一列刪除才可。由於不明原因,輸出結果經常會顯示超出列表范圍。
三、主題頁面的結構特征分析
首先,本次爬蟲爬取NBA中國官方網站(https://china.nba.com/statistics/)球員排名及各項數據
1.頁面信息
在頁面中找到Network(網絡)之后,再找到XHR之后,刷新頁面,獲取到該網頁的一些數據。找到保存數據的json文件
2.對json文件進行數據提取
在上一步查詢的結果數據中篩選json文件找到正確的json文件之后,查詢預覽的結果,可以看到與需要爬取的信息相符,就是我們需要的庫。
確定json文件信息是正確且需要的之后,再查詢標頭,找到user—URL。
之后開始我們對NBA中國官方網站球員數據的抓包。
四、網絡爬蟲程序設計
1.數據爬取與采集
#爬取網頁數據
#提取數據 import requests from bs4 import BeautifulSoup import json import numpy as np # url='https://china.nba.cn/stats2/league/playerstats.json?conference=All&country=All&individual=All&locale=zh_CN&pageIndex=0&position=All&qualified=false&season=2021&seasonType=2&split=All+Team&statType=points&team=All&total=perGame' # def getHTMLText(url,timeout=30): try: r=requests.get(url,timeout=30) # r.raise_for_status() r.encoding=r.apparent_encoding return r.text except: return'產生異常' #html.parser表示用BeautifulSoup庫解析網頁 html=getHTMLText(url) soup=BeautifulSoup(html,'html.parser') print(soup.prettify())
結果如下:
#采集數據
#創建空表 pointsPg_list=[] assistsPg_list=[] rebsPg_list=[] name_list=[] data1=[] tppct=[] ftpct=[] fgpct=[] stealsPg_list=[] blocksPg_list=[] offRebsPg_list=[] defRebsPg_list=[] rank=[] html=getHTMLText(url) data=json.loads(html) a=data['payload']['players'] data1.append(name_list) data1.append(assistsPg_list) b=1 for i in a: rank.append(b) name_list.append(i['playerProfile']['displayName']) pointsPg_list.append(i['statAverage'][ 'pointsPg']) rebsPg_list.append(i['statAverage'][ 'rebsPg']) assistsPg_list.append(i['statAverage'][ 'assistsPg']) stealsPg_list.append(i['statAverage'][ 'stealsPg']) blocksPg_list.append(i['statAverage'][ 'blocksPg']) offRebsPg_list.append(i['statAverage'][ 'offRebsPg']) defRebsPg_list.append(i['statAverage'][ 'defRebsPg']) tppct.append(i['statAverage']['tppct']) ftpct.append(i['statAverage']['ftpct']) fgpct.append(i['statAverage']['fgpct']) b=b+1 list_1=['排名'] #導出球員的各項數據 import pandas as pd df=pd.DataFrame(columns=list_1) df['排名']=rank df['NAME']=name_list df['場均得分']=pointsPg_list df['場均籃板']=rebsPg_list df['場均助攻']=assistsPg_list df['投籃命中率']=fgpct df['三分命中率']=tppct df['罰球命中率']=ftpct df['進攻效率']=offRebsPg_list df['防守效率']=defRebsPg_list df['場均搶斷']=stealsPg_list df['場均蓋帽']=blocksPg_list df=df.drop_duplicates() df
結果如下:
#保存數據
#將dataframe寫入csv df.to_csv('D:/Python/NBA數據.csv',index=False) df.to_csv('D:/Python/NBA.csv',index=False)
2.對數據進行清洗和處理
#檢查重復值
#檢查並顯示重復值 print(df.duplicated())
#刪除重復值
#刪除重復值 df = df.drop_duplicates() df.head(
#檢查是否有空值
#檢查是否有空值 print(df['NAME'].isnull().value_counts())
#異常值處理
#異常值處理 df.describe()
#查看統計信息
#查看統計信息 print(df.describe()
3、數據分析與可視化(例如:數據柱形圖、折線圖圖、散點圖、回歸圖、分布圖)
#數據可視化
#繪制柱狀圖
#繪制柱狀圖 import pandas as pd import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] plt.bar(df.排名, df.投籃命中率, color='b') plt.xlabel("排名") plt.ylabel("投籃命中率") plt.title('排名與投籃命中率柱狀圖') plt.show()
結果:
#繪制散點圖
#繪制散點圖 import pandas as pd import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負號 size=30 plt.scatter(df.排名, df.場均得分,size, color='b',alpha=0.6,marker='o') plt.xlabel("排名") plt.ylabel("場均得分") plt.title('排名與場均得分柱狀圖') plt.show()
結果:
#繪制堆疊圖
#繪制罰球命中率與排名圖 import pandas as pd import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負號 plt.stackplot(df.排名, df.罰球命中率, color=['b',]) plt.xlabel("排名") plt.ylabel("罰球命中率") plt.title('排名與罰球命中率堆疊圖') plt.show()
結果:
#繪制折線圖
#繪制折線圖 import pandas as pd import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus'] = False plt.plot(df.排名, df.三分命中率, color='b') plt.xlabel("排名") plt.ylabel("三分命中率") plt.title('排名與三分命中率折線圖') plt.show()
結果:
4.數據處理分析
#求回歸系數
#求取回歸系數 from sklearn.linear_model import LinearRegression X=df.drop('NAME',axis=1) predict_model=LinearRegression() predict_model.fit(X,df['排名']) print('回歸系數為:',predict_model.coef_)
結果求得:
#繪制回歸圖
#繪制回歸圖 import seaborn as sns import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei']#用來正常顯示中文標簽 X=df.drop('NAME',axis=1) sns.regplot(df['排名'],df['進攻效率']) sns.regplot(df['排名'],df['防守效率']) plt.title('排名與進攻、防守效率圖')
結果:
通過以上的分析,我們可以發現在排名與一些其他數據的比較之中,呈現出起伏的變化,可以得知一些場均得分排在前面的球員,在各項命中率,防守、進攻效率以及場均能得到的搶斷和防守並沒有比排在他們之后的一些球員高。從現實上的比賽來看,出手數對得分起到了一定的影響,導致場均得分較低。
5.根據數據之間的關系,分析兩個變量之間的相關系數,畫出散點圖,並建立變量之間的回歸方程(一元或多元)。
#選擇場均得分以及進攻效率,防守效率和場均搶斷四個特征變量,用最小二乘法分析兩個變量間的二次擬合方程和擬合曲線
#繪制擬合曲線
1.進攻效率與場均得分
#繪制擬合曲線 import matplotlib.pyplot as plt import matplotlib import numpy as np import scipy.optimize as opt import csv x0=df['進攻效率'] y0=df['場均得分'] def func(x,c): k,a=c return k*x+a def errfc(c,x,y): return y-func(x,c) c0=(100,20) #調用擬合曲線 print(opt.leastsq(errfc,c0,args=(x0,y0))) #s設置畫布 chinese=matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\simsun.ttc') plt.plot(x0,y0,"o",label=u"進攻效率") plt.plot(x0,func(x0,opt.leastsq(errfc,c0,args=(x0,y0))[0]),label=u"場均得分") plt.title('進攻效率與場均得分擬合曲線圖') plt.legend(loc=3,prop=chinese) plt.show()
結果:
2.防守效率與場均搶斷
#繪制擬合曲線 import matplotlib.pyplot as plt import matplotlib import numpy as np import scipy.optimize as opt import csv x0=df['防守效率'] y0=df['場均搶斷'] # def func(x,c): k,a=c return k*x+a def errfc(c,x,y): return y-func(x,c) c0=(100,20) #調用擬合曲線 print(opt.leastsq(errfc,c0,args=(x0,y0))) #s設置畫布 chinese=matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\simsun.ttc') plt.plot(x0,y0,"o",label=u"防守效率") plt.plot(x0,func(x0,opt.leastsq(errfc,c0,args=(x0,y0))[0]),label=u"場均搶斷") plt.title('防守效率與場均搶斷擬合曲線圖') plt.legend(loc=3,prop=chinese) plt.show()
結果:
6、數據持久化
#數據持久化 df = pd.DataFrame(df,columns=['排名','NAME','場均得分','場均籃板','場均助攻','投籃命中率','罰球命中率','三分命中率','進攻效率','防守效率','場均搶斷','場均蓋帽']) df.to_csv('NBA.csv',encoding = 'gbk') #保存文件,數據持久化
7、將以上各部分的代碼匯總,附上完整程序代碼
1 #提取數據 2 import requests 3 from bs4 import BeautifulSoup 4 import json 5 # 6 url='https://china.nba.cn/stats2/league/playerstats.json?conference=All&country=All&individual=All&locale=zh_CN&pageIndex=0&position=All&qualified=false&season=2021&seasonType=2&split=All+Team&statType=points&team=All&total=perGame' 7 # 8 def getHTMLText(url,timeout=30): 9 try: 10 r=requests.get(url,timeout=30) # 11 r.raise_for_status() 12 r.encoding=r.apparent_encoding 13 return r.text 14 except: 15 return'產生異常' 16 17 #html.parser表示用BeautifulSoup庫解析網頁 18 html=getHTMLText(url) 19 soup=BeautifulSoup(html,'html.parser') 20 print(soup.prettify()) 21 22 #創建空表 23 pointsPg_list=[] 24 assistsPg_list=[] 25 rebsPg_list=[] 26 name_list=[] 27 data1=[] 28 tppct=[] 29 ftpct=[] 30 fgpct=[] 31 stealsPg_list=[] 32 blocksPg_list=[] 33 offRebsPg_list=[] 34 defRebsPg_list=[] 35 rank=[] 36 html=getHTMLText(url) 37 data=json.loads(html) 38 a=data['payload']['players'] 39 data1.append(name_list) 40 data1.append(assistsPg_list) 41 b=1 42 for i in a: 43 rank.append(b) 44 name_list.append(i['playerProfile']['displayName']) 45 pointsPg_list.append(i['statAverage'][ 'pointsPg']) 46 rebsPg_list.append(i['statAverage'][ 'rebsPg']) 47 assistsPg_list.append(i['statAverage'][ 'assistsPg']) 48 stealsPg_list.append(i['statAverage'][ 'stealsPg']) 49 blocksPg_list.append(i['statAverage'][ 'blocksPg']) 50 offRebsPg_list.append(i['statAverage'][ 'offRebsPg']) 51 defRebsPg_list.append(i['statAverage'][ 'defRebsPg']) 52 tppct.append(i['statAverage']['tppct']) 53 ftpct.append(i['statAverage']['ftpct']) 54 fgpct.append(i['statAverage']['fgpct']) 55 b=b+1 56 list_1=['排名'] 57 58 #導出球員的各項數據 59 import pandas as pd 60 df=pd.DataFrame(columns=list_1) 61 df['排名']=rank 62 df['NAME']=name_list 63 df['場均得分']=pointsPg_list 64 df['場均籃板']=rebsPg_list 65 df['場均助攻']=assistsPg_list 66 df['投籃命中率']=fgpct 67 df['三分命中率']=tppct 68 df['罰球命中率']=ftpct 69 df['進攻效率']=offRebsPg_list 70 df['防守效率']=defRebsPg_list 71 df['場均搶斷']=stealsPg_list 72 df['場均蓋帽']=blocksPg_list 73 df 74 75 #將dataframe寫入csv 76 df.to_csv('D:/Python/NBA數據.csv',index=False) 77 df.to_csv('D:/Python/NBA.csv',index=False) 78 79 #檢查並顯示重復值 80 print(df.duplicated()) 81 82 #刪除重復值 83 df = df.drop_duplicates() 84 df.head() 85 86 #異常值處理 87 df.describe() 88 89 #檢查是否有空值 90 print(df['排名'].isnull().value_counts()) 91 92 #查看統計信息 93 print(df.describe()) 94 df 95 96 #求取回歸系數 97 from sklearn.linear_model import LinearRegression 98 X=df.drop('NAME',axis=1) 99 predict_model=LinearRegression() 100 predict_model.fit(X,df['排名']) 101 print('回歸系數為:',predict_model.coef_) 102 103 #繪制回歸圖 104 import seaborn as sns 105 import matplotlib.pyplot as plt 106 plt.rcParams['font.sans-serif']=['SimHei']#用來正常顯示中文標簽 107 X=df.drop('NAME',axis=1) 108 sns.regplot(df['排名'],df['進攻效率']) 109 sns.regplot(df['排名'],df['防守效率']) 110 plt.title('排名與進攻、防守效率圖') 111 112 #繪制柱狀圖 113 import pandas as pd 114 import numpy as np 115 import matplotlib.pyplot as plt 116 plt.rcParams['font.sans-serif']=['SimHei'] 117 plt.bar(df.排名, df.投籃命中率, color='b') 118 plt.xlabel("排名") 119 plt.ylabel("投籃命中率") 120 plt.title('排名與投籃命中率柱狀圖') 121 plt.show() 122 123 #繪制散點圖 124 import pandas as pd 125 import numpy as np 126 import matplotlib.pyplot as plt 127 plt.rcParams['font.sans-serif']=['SimHei'] 128 plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負號 129 size=30 130 plt.scatter(df.排名, df.場均得分,size, color='b',alpha=0.6,marker='o') 131 plt.xlabel("排名") 132 plt.ylabel("場均得分") 133 plt.title('排名與場均得分柱狀圖') 134 plt.show() 135 136 #罰球命中率與排名 137 import pandas as pd 138 import numpy as np 139 import matplotlib.pyplot as plt 140 plt.rcParams['font.sans-serif']=['SimHei'] 141 plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負號 142 plt.stackplot(df.排名, df.罰球命中率, color=['b',]) 143 plt.xlabel("排名") 144 plt.ylabel("罰球命中率") 145 plt.title('排名與罰球命中率堆疊圖') 146 plt.show() 147 148 #繪制折線圖 149 import pandas as pd 150 import numpy as np 151 import matplotlib.pyplot as plt 152 plt.rcParams['font.sans-serif']=['SimHei'] 153 plt.rcParams['axes.unicode_minus'] = False 154 plt.plot(df.排名, df.三分命中率, color='b') 155 plt.xlabel("排名") 156 plt.ylabel("三分命中率") 157 plt.title('排名與三分命中率折線圖') 158 plt.show() 159 160 #繪制擬合曲線 161 import matplotlib.pyplot as plt 162 import matplotlib 163 import numpy as np 164 import scipy.optimize as opt 165 import csv 166 x0=df['進攻效率'] 167 y0=df['場均得分'] 168 def func(x,c): 169 k,a=c 170 return k*x+a 171 def errfc(c,x,y): 172 return y-func(x,c) 173 c0=(100,20) 174 #調用擬合曲線 175 print(opt.leastsq(errfc,c0,args=(x0,y0))) 176 #s設置畫布 177 chinese=matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\simsun.ttc') 178 179 plt.plot(x0,y0,"o",label=u"進攻效率") 180 181 plt.plot(x0,func(x0,opt.leastsq(errfc,c0,args=(x0,y0))[0]),label=u"場均得分") 182 plt.title('進攻效率與場均得分擬合曲線圖') 183 plt.legend(loc=3,prop=chinese) 184 185 plt.show() 186 187 #繪制擬合曲線 188 import matplotlib.pyplot as plt 189 import matplotlib 190 import numpy as np 191 import scipy.optimize as opt 192 import csv 193 x0=df['防守效率'] 194 y0=df['場均搶斷'] 195 # 196 def func(x,c): 197 k,a=c 198 return k*x+a 199 def errfc(c,x,y): 200 return y-func(x,c) 201 c0=(100,20) 202 #調用擬合曲線 203 print(opt.leastsq(errfc,c0,args=(x0,y0))) 204 #s設置畫布 205 chinese=matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\simsun.ttc') 206 207 plt.plot(x0,y0,"o",label=u"防守效率") 208 209 plt.plot(x0,func(x0,opt.leastsq(errfc,c0,args=(x0,y0))[0]),label=u"場均搶斷") 210 plt.title('防守效率與場均搶斷擬合曲線圖') 211 plt.legend(loc=3,prop=chinese) 212 213 plt.show() 214 215 #數據持久化 216 df = pd.DataFrame(df,columns=['排名','NAME','場均得分','場均籃板','場均助攻','投籃命中率','罰球命中率','三分命中率','進攻效率','防守效率','場均搶斷','場均蓋帽']) 217 df.to_csv('NBA.csv',encoding = 'gbk') #保存文件,數據持久化
五、總結
1.經過對主題數據的分析與可視化,可以得到哪些結論?是否達到預期的目標?
通過一系列的數據分析及可視化可以發現,在爬取的這些球員之中,根據場均得分來進行的排名,事實上並不是能那么可靠地分析一個球員的好與壞,在場上不僅僅只有得分,還有其余的各項數據,投籃的命中率以及防守、進攻效率和對球隊的1幫助很大程度上並不是根據場均得分來體現,得分高命中率低,可能會導致球隊落后和失分。經過一系列數據對比我們可以的到此結論,達到了預期的目標。
2.在完成此設計過程中,得到哪些收獲?以及要改進的建議?
在完成設計的過程中,由於選題以及對爬取知識的欠缺耗費了大量的時間,期間瀏覽、了解、和學習了許多老師推薦的優秀作品,以及CSDN,博客園里的許多博主發布的很好的作品,讓我得到也學到了很多的新的知識,學到了很多不同的完善和解決同一個問題的方法,但是還沒有完全掌握並使用使之成為自己的東西,還需要在課后進行更仔細的研究。在完成設計的過程中,需要感謝一些掌握知識比較透徹的同學對我出現的問題的指正。在繪制分析圖時課本里的例題分析講解的也比較透徹,當然這些知識在課上也都很清楚地進行過講解,在課后作業中也進行了多次練習。在設計中,存在很多的不足之處,但是,通過這次設計能讓我更好地警醒自己的Python水平和理解的有限。同樣,這些不足會給我更大的動力去探索Python。總而言之,這次的設計很大程度,很大意義上對我起到了巨大的幫助和督促。課下的空余時間依然要不斷努力學習新的知識完善自己。