Python爬虫学习之NBA球员可视化分析
前言
最近刚上完Python选修课,一直挺喜欢Python的,觉得Python的简洁优美的代码像是在写诗一样让人看了赏心悦目,其次就是他强大的第三方库是其他语言所不能媲美的.有很多你需要用的功能,其实不需要学习他的底层架构,大多数情况下只用知道他的api接口就足够了.最后就是Python的爬取数据,科学计算的功能与最近很火的AI接轨,符合时代潮流
这次项目是来源于学校在假期的一个实训项目,由于自己是一名资深篮球爱好者,所以就选了这个项目.
文章目录
选取目标网站
我选取的是 NBA中国官网,最权威的数据
对网站数据的理解
我们开始学习的是对html静态数据的爬取,可是大部分网站都是通过ajax,或者其他技术动态获取技术的,所以要对网站中的动态获取的部分进寻找
- 打开开发者模式,在network的XHR中寻找动态获取的环节在其中寻找你想要获取数据的部分
数据爬取
数据爬取的流程
def main(): #主程序
print("开始爬取.....")
year=2010 #起始年份
baseurl='https://china.nba.com/static/data/league/playerstats_All_All_All_0_All_false_2018_2_All_Team_points_All_perGame.json'
#获得数据
NBAPlayerdatadict=getdata(baseurl,year)
#所需信息的抬头列表
cols_index2 = ['displayName',"code", 'position', 'name',"code",'games','points', 'pointsPg', 'rebsPg', 'assistsPg''minsPg', 'fgpct', 'tppct', 'ftpct', 'blocksPg', 'foulsPg', 'height', 'weight'
]
cols_index1 = ['playerProfile','playerProfile', 'playerProfile', 'teamProfile',
'teamProfile', 'statAverage',
'statTotal', 'statAverage', 'statAverage', 'statAverage',
'statAverage', 'statAverage', 'statAverage', 'statAverage',
'statAverage', 'statAverage', 'playerProfile', 'playerProfile'
]
#保存数据
savepath='.//'+str(year)+'年-2020年NBA球员数据排行TOP50.xls'
savedata(NBAPlayerdatadict,savepath,year,cols_index1,cols_index2)
#数据库位置
dbpath='.//NBA球员数据库.db'
#将数据保存到数据库
saveDB(NBAPlayerdatadict,dbpath,year,cols_index1,cols_index2)
print('成功爬取并保存数据!')
开始数据爬取,首先第一步你要将自己伪装成一个浏览器,所以在你请求获得数据的时候就要把自己的身份证(user-agent)写成浏览器的
这里利用python的内置包urllib.request&error来模拟向浏览器发出请求,废话不多说上代码
def askUrl(url): #获得请求得到一个html(字符串的形式)
headers={ #伪装身份信息
'User-Agent': 'Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 80.03987.122Safari / 537.36'
}
request = urllib.request.Request(url,headers=headers)
html=''
try:
response=urllib.request.urlopen(request) #提交
html=response.read().decode('UTF-8')
print("成功爬取到html!")
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
if isinstance(e.reason, socket.timeout):
print('time out!')
return html
数据解析
-
由于获取到的数据(html)是php格式需要对文件进行正则表达式处理之后获得json数据格式
-
利用json包对数据进行json解析,获得字典数据NBAPlayerdatadict
-
利用列表对数据进行查找,获得我们想要的数据
def getdata(baseurl,year): #爬取网页获得需要的数据
Playerdatadict={}
for i in range(year,2020):
#创建模式匹配更换url获取不同年份的data
pattern_date = re.compile(r'(_\d*?_\d)', re.S)
newbaseurl = re.sub(pattern_date, '_'+str(i)+'_2', baseurl)
html=askUrl(newbaseurl)
# 将html中的文件进行json解析得到Playerdata字典
Playerdata=json.loads(html)
# 将Playerdata放大字典中并带上年份
Playerdatadict.setdefault(str(i)+"年", {}).update(Playerdata)
time.sleep(0.05) # 设置爬虫间隔
print('成功获取数据!')
return Playerdatadict
数据保存
我们需要将数据保存到excel文件,利用xlwt库创建多个sheet工作表,将不同年份的数据保存在里面
def savedata(Playerdatadict,savepath,year,cols_index1,cols_index2): #保存数据到Excel
cols=['排名','球员','球员链接','位置','球队','球队链接',
'出场数','赛季得分','场均得分','场均篮板',
'场均助攻','分钟','命中率','三分命中率(%)',
'罚球命中率','场均盖帽','场均失误','身高(m)','体重']
workbook = xlwt.Workbook(encoding='UTF-8') # 创建workbook
for i in range(year, 2020):
worksheet = workbook.add_sheet(str(i) + '年') # 创建工作表
for j in range(len(cols)):
worksheet.write(0,j,cols[j])
for k in range(len(Playerdatadict[str(i) + '年']['payload']['players'])):
worksheet.write(k + 1, 0, k + 1)
for n in range(len(cols_index1)):
p_link = r'https://china.nba.com/players/#!/'
t_link = r'https://china.nba.com/'
# 从Playerdatadict将有效信息取出来
Playerdatadict_info = Playerdatadict[str(i) + "年"]['payload']['players'][k][cols_index1[n]][
cols_index2[n]]
if n != 1 and n != 4:
worksheet.write(k + 1, n + 1, Playerdatadict_info)
elif n == 1: # 球员链接+str(link)
worksheet.write(k + 1, n + 1, p_link + Playerdatadict_info)
else:
worksheet.write(k + 1, n + 1, t_link + Playerdatadict_info)
workbook.save(savepath)
print('保存数据成功!')
将数据保存到数据库中,这里呢我用的是sqlite,一个轻量级嵌入在pycharm的数据库,比较简单,数据库的原理其实都一样,换其他数据库也是大同小异
首先初始化数据库
def initDB(tablename,dbpath):
sql = '''
create table ''' + str(tablename) + '''(
ranking integer primary key autoincrement,
name text,
name_link text,
position text,
teamname text,
team_link text,
games integer ,
points integer ,
averpoints integer ,
averrebound integer,
averassist integer ,
minutes integer ,
fgpct integer,
tppct integer,
ftpct integer ,
averblocks integer ,
averfouls integer,
height integer,
weight text
);
'''
con = sqlite3.connect(dbpath) # 连接数据库
c = con.cursor() # 创建游标
c.execute(sql)
con.commit()
c.close()
con.close()
print('表' + str(tablename) + "创建成功!")
把数据放到数据库中
def saveDB(Playerdatadict,dbpath,year,cols_index1,cols_index2): #保存数据到数据库
for i in range(year, 2020):
#表的名称
tablename="球员数据"+str(i)+'年'
#初始化数据库
initDB(tablename,dbpath)
con=sqlite3.connect(dbpath)
c=con.cursor()
#Playerdatadict_info为从Playerdatadict字典里面提取到的有用信息
Playerdatadict_info = Playerdatadict[str(i) + "年"]['payload']['players']
for j in range(len(Playerdatadict_info)): #球员信息个数len(Playerdatadict_info)
data_need = [] # 每一行所需信息
for k in range(len(cols_index1)):
# 从Playerdatadict将有效信息取出来
info = Playerdatadict_info[j][cols_index1[k]][cols_index2[k]]
p_link = r'https://china.nba.com/players/#!/'
t_link = r'https://china.nba.com/'
if k!= 1 and k!= 4:
data_need.append(str(info))
elif k==1:
data_need.append(p_link+str(info))
else:
data_need.append(t_link + str(info))
for index in range(len(data_need)):
data_need[index] = '"' + data_need[index] + '"'
sql = '''
insert into '''+str(tablename)+'''(
name,name_link,position,teamname,team_link,games,points,averpoints,averrebound,averassist,minutes,fgpct,tppct,ftpct,averblocks,averfouls,height,weight)
values (%s)'''%(",".join(data_need))
c.execute(sql)
con.commit()
c.close()
con.close()
print('数据成功保存到数据库!')
数据爬取工作完毕!
利用flask框架进行网站的搭建
这里python web推荐使用flask框架flask官方中文文档
Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。Flask使用 BSD 授权
Flask 很轻,花很少的成本就能够开发一个简单的网站。非常适合初学者学习。Flask 框架学会以后,可以考虑学习插件的使用。 如果你后续要用到更多的功能他还有各种各样的拓展包
这个我只用了flask的三个功能
from flask import Flask,render_template,request
import sqlite3,jieba
app = Flask(__name__)
@app.route('/') #地址路由
def welcome():
return render_template('index.html')
@app.route('/index')
def index():
return welcome()
@app.route('/top50')
def top50():
datalist = []
con = sqlite3.connect("NBA球员数据库.db")
c = con.cursor()
#设置当前页数
page=int(request.args.get('page',1))
year=int(page)+2009
sql= '''
select * from 球员数据'''+str(year)+'''年
'''
data=c.execute(sql)
for item in data:
datalist.append(item)
c.close()
con.close()
# 设置总页码数
pagemax = 10
return render_template('top50.html',datalist=datalist,page=page,pagemax=pagemax)
@app.route('/cloud')
def cloud():
return render_template('cloud.html')
@app.route('/chart')
def chart():
datalist = []
years=[] #年份
xx=[]#x坐标数据
#存放球队的名称的列表
team=[['76人'], ['公牛'], ['凯尔特人'], ['勇士'], ['国王'], ['太阳'], ['奇才'], ['小牛'], ['尼克斯'], ['开拓者'], ['快船'], ['掘金'], ['森林狼'], ['步行者'], ['活塞'], ['湖人'], ['火箭'], ['灰熊'], ['热火'], ['爵士'], ['猛龙'], ['篮网'], ['老鹰'], ['雄鹿'], ['雷霆'], ['马刺'], ['骑士'], ['魔术'], ['鹈鹕'], ['黄蜂']]
#存放球队名称的字符串
# 存放字符的字符串
text = ''
con = sqlite3.connect("NBA球员数据库.db")
c = con.cursor()
# 设置当前页数
page = 1
year = int(page) + 2009
for i in range(year, 2020):
data_peryear = []
years.append(i)
sql = '''
select * from 球员数据''' + str(i) + '''年
'''
data = c.execute(sql)
for item in data:
data_peryear.append(item)
#将球队名称练成字符串
text += item[4]
datalist.append(data_peryear)
for index in range(10):
xx.append(str(index+2010)+str(datalist[index][0][1]))
c.close()
con.close()
#利用字符串统计球队名称出现的次数
for i in range(len(team)):
number=text.count(team[i][0])
team[i].append(str(number))
return render_template('chart.html',datalist=datalist,years=years,xx=xx,team=team)
@app.route('/team')
def team():
return render_template('team.html')
if __name__ == '__main__':
app.run(debug=True)
wordcloud库生成词云
利用wordcloud库和jieba库对获取到的teamname和playername进行词云统计生成词云,得出出现次数最多的球员和球队
```python
import jieba
from matplotlib import pyplot as plt
import matplotlib.colors as colors
from wordcloud import WordCloud
from PIL import Image #图片处理
import numpy as np
import sqlite3
import random
def random_color_func(word=None, font_size=None, position=None, orientation=None, font_path=None, random_state=None):
h = random.randint(150,250)
s = int(100.0 * 255.0 / 255.0)
l = int(100.0 * float(random.randint(60, 120)) / 255.0)
return "hsl({}, {}%, {}%)".format(h, s, l)
def playername():
con = sqlite3.connect("NBA球员数据库.db")
c = con.cursor()
# 起始年份
year = 2010
# 存放字符的字符串
text = ''
for i in range(year, 2020):
sql = '''
select name from 球员数据''' + str(i) + '''年
'''
data = c.execute(sql)
for item in data:
text += item[0]
cut = jieba.cut(text)
string = ",".join(cut)
print(string)
c.close()
con.close()
img = Image.open(r'./static/assets/img/NBA.png') # 打开图片
img_array = np.array(img) # 将图片转化为数组
wc = WordCloud(
background_color='white',
mask=img_array,
font_path="msyh.ttc",
color_func=random_color_func
)
wc.generate_from_text(string)
# 绘制图片
fig = plt.figure(1)
plt.imshow(wc)
plt.axis('off')
# plt.show()
plt.savefig(r'./static/assets/img/namecloud.png', dpi=1000)
def teamname():
con = sqlite3.connect("NBA球员数据库.db")
c = con.cursor()
# 起始年份
year = 2010
# 存放字符的字符串
text = ''
for i in range(year, 2020):
sql = '''
select teamname from 球员数据''' + str(i) + '''年
'''
data = c.execute(sql)
for item in data:
text += item[0]
cut = jieba.cut(text)
string = ",".join(cut)
print(string)
c.close()
con.close()
img = Image.open(r'./static/assets/img/乔1.jpg') # 打开图片
img_array = np.array(img) # 将图片转化为数组
wc = WordCloud(
background_color='white',
mask=img_array,
font_path="msyh.ttc",
color_func=random_color_func
)
wc.generate_from_text(string)
# 绘制图片
fig = plt.figure(1)
plt.imshow(wc)
plt.axis('off')
# plt.show()
plt.savefig(r'./static/assets/img/teamcloud.png', dpi=900)
``
利用echarts进行可视化分析
ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。 echarts官方文档
利用后端的数据制作饼状图和柱状图将数据可视化
网站成果