Python高级应用程序设计任务
Python高级应用程序设计任务要求
用Python实现一个面向主题的网络爬虫程序,并完成以下内容:
(注:每人一题,主题内容自选,所有设计内容与源代码需提交到博客园平台)
一、主题式网络爬虫设计方案
1.主题式网络爬虫名称
《Python爬虫之NBA球队数据的爬取及分析》
2.主题式网络爬虫爬取的内容与数据特征分析
爬取内容:本次对于“NBA官网”网站爬取的内容是:排名,球队名,场均篮板,场数,失误,抢断,场均助攻来观察球队之间的差距到底在哪里,可通过后续绘制直方图、折线图等观察数据的变化情况。
3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)
本次主题式网络爬虫不仅包括了对网站的爬取,也包括对所爬取数据的清洗及分析,对我们的个人能力是一次巨大的提升。本次要爬取的“国家统计局”网站的相关内容,进行网站爬取首要先了解该网站的页面结构,通过分析,该网站的表单属于后台js提交的方式,也就是所谓的动态网页,传统的对于静态网页是爬取方法是行不通的,再对页面进一步分析后,发现元素审查后可获取到后台表单提交的URL,通过该URL可进行后续的爬取工作。后续将所爬取到的内容以excel的形式保存到本地电脑上,以实现数据的持久化,再通过该excel进行数据的清洗及分析,提取所爬取的目标内容,绘制对应图形,得出相应结论。
技术难点:对动态网站的数据获取的URL难发现、所要的爬取的数据分布在网页的不同深度。
二、主题页面的结构特征分析
1.主题页面的结构特征
(
三、网络爬虫程序设计
1.数据爬取与采集
1 import requests 2 from bs4 import BeautifulSoup 3 import json 4 r=requests.get('https://china.nba.cn/stats2/league/teamstats.json?conference=All&division=All&locale=zh_CN&season=2021&seasonType=2') 5 r.encoding="utf-8" 6 data=json.loads(r.text) 7 print(data) 8 b=data['payload']['teams'] 9 for i in b: 10 print(i) 11 name=[] 12 for i in b: 13 name.append(i['profile']['name']) 14 for i in b: 15 pointsPg.append(i['statAverage']['pointsPg']) 16 rebsPg=[] 17 for i in b: 18 rebsPg.append(i['statAverage']['rebsPg']) 19 games=[] 20 for i in b: 21 games.append(i['statAverage']['games']) 22 turnoversPg=[] 23 for i in b: 24 turnoversPg.append(i['statAverage']['turnoversPg']) 25 stealsPg=[] 26 for i in b: 27 stealsPg.append(i['statAverage']['stealsPg']) 28 assistsPg=[] 29 for i in b: 30 assistsPg.append(i['statAverage']['assistsPg']) 31 rank=[] 32 for i in range(1,31): 33 rank.append(i) 34 print(name) 35 print(pointsPg) 36 print(rebsPg) 37 print(games) 38 print(turnoversPg) 39 print(stealsPg) 40 print(assistsPg) 41 import pandas as pd 42 df=pd.DataFrame({'排名':rank, 43 '球队名':name, 44 '场均篮板':rebsPg, 45 '场数':games, 46 '失误':turnoversPg, 47 '抢断':stealsPg, 48 '场均助攻':assistsPg, 49 }) 50 df
51 df.to_csv('D:\python\球队数据.csv',index=False)
1 import matplotlib 2 chinese=matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\simsun.ttc') 3 import matplotlib as mpl 4 mpl.rcParams['font.sans-serif'] = ["SimHei"] 5 mpl.rcParams["axes.unicode_minus"] = False 6 import matplotlib.pyplot as plt 7 plt.figure(figsize=(10,6)) 8 x=rank[0:5] 9 x1=name[0:5] 10 a=['a','b','c'] 11 total_width,n=0.8,3 12 #设置间距 13 width=total_width/n 14 #在偏移间距位置绘制柱状图1 15 for i in range(len(x)): 16 x[i]-=width 17 plt.bar(x1,rebsPg[0:5],label='场均篮板',fc='teal') 18 #设置数字标签 19 for a,b in zip(x,rebsPg[0:5]): 20 plt.text(a,b,b,ha='center',va='bottom',fontsize=10) 21 #在偏移间距位置绘制柱状图2 22 for i in range(len(x)): 23 x[i]+=width 24 plt.bar(x,turnoversPg[0:5],label='失误',tick_label=name,fc='darkorange') 25 for a,b in zip(x1,turnoversPg[0:5]): 26 plt.text(a,b,b,ha='center',va='bottom',fontsize=10) 27 #在偏移间距位置绘制柱状图3 28 for i in range(len(x)): 29 x[i]+=width 30 plt.bar(x,assistsPg[0:5],label='场均助攻',fc='lightcoral') 31 for a,b in zip (x1,assistsPg[0:5]): 32 plt.text(a,b,b,ha='center',va='bottom',fontsize=10)
1 import seaborn as sns 2 sns.regplot(df['排名'],df['场均篮板'])
1 data=pd.Series(games[0:8],name[0:8]) 2 data.plot(kind='bar',title='场数') 3 plt.show()
1 import matplotlib.pyplot as plt 2 plt.rcParams['font.sans-serif']='SimHei'#设置中文显示 3 plt.figure(figsize=(6,6))#将画布设定为正方形,则绘制的饼图是正圆 4 label=name[0:5]#定义饼图的标签,标签是列表 5 explode=[0.01,0.01,0.01,0.01,0.01]#设定各项距离圆心n个半径 6 #plt.pie(values[-1,3:6],explode=explode,labels=label,autopct='%1.1f%%')#绘制饼图 7 values=turnoversPg[0:5] 8 plt.pie(values,explode=explode,labels=label,autopct='%1.1f%%')#绘制饼图 9 plt.title('排名前5的失误比例')#绘制标题 10 plt.savefig('./')#保存图片 11 plt.show()
1 #画出散点图 2 plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 3 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 4 N=10 5 x=np.random.rand(N) 6 y=np.random.rand(N) 7 size=50 8 plt.xlabel("排名") 9 plt.ylabel("热度") 10 plt.scatter(x,y,size,color='r',alpha=0.5,marker="o") 11 #散点图 kind='reg' 12 sns.jointplot(x="排名",y="失误",data=df,kind='reg') 13 # kind='hex' 14 sns.jointplot(x="排名",y="失误",data=df,kind='hex') 15 # kind='kde' 16 sns.jointplot(x="排名",y="失误",data=df,kind="kde",space=0,color='g')
1 data=pd.Series(stealsPg[0:8],name[0:8]) 2 data.plot(kind='bar',title='抢断') 3 plt.show()
import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']='SimHei'#设置中文显示 plt.figure(figsize=(6,6))#将画布设定为正方形,则绘制的饼图是正圆 label=name[25:30]#定义饼图的标签,标签是列表 explode=[0.01,0.01,0.01,0.01,0.01]#设定各项距离圆心n个半径 #plt.pie(values[-1,3:6],explode=explode,labels=label,autopct='%1.1f%%')#绘制饼图 values=turnoversPg[25:30] plt.pie(values,explode=explode,labels=label,autopct='%1.1f%%')#绘制饼图 plt.title('排名后5名的失误比例')#绘制标题 plt.savefig('./')#保存图片 plt.show()
1 X = df.排名 2 Y = df.场均篮板 3 def A(): 4 plt.scatter(X,Y,color="blue",linewidth=2) 5 plt.title("场均篮板的散点图",color="blue") 6 plt.grid() 7 plt.show() 8 def B(): 9 plt.scatter(X,Y,color="green",linewidth=2) 10 plt.title("redu",color="blue") 11 plt.grid() 12 plt.show() 13 def func(p,x): 14 a,b,c=p 15 return a*x*x+b*x+c 16 def error(p,x,y): 17 return func(p,x)-y 18 def main(): 19 plt.figure(figsize=(10,6)) 20 p0=[0,0,0] 21 Para = leastsq(error,p0,args=(X,Y)) 22 a,b,c=Para[0] 23 print("a=",a,"b=",b,"c=",c) 24 plt.scatter(X,Y,color="blue",linewidth=2) 25 x=np.linspace(0,20,20) 26 y=a*x*x+b*x+c 27 plt.plot(x,y,color="blue",linewidth=2,) 28 plt.title("场均篮板数分布") 29 plt.grid() 30 plt.show() 31 print(A()) 32 print(B()) 33 print(main())
1 #绘制“场均助攻”的直方图 2 import matplotlib.pyplot as plt 3 import pandas as pd 4 import numpy as np 5 plt.rcParams['font.sans-serif'] = ['KaiTi'] # 指定默认字体 6 plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题 7 df['场均助攻'].plot(kind='bar',figsize=(15,10)) 8 plt.suptitle('场均助攻',fontsize=20) 9 plt.xticks(fontsize=20) #修改x轴字体大小为20 10 plt.yticks(fontsize=20) #修改y轴字体大小为20 11 plt.xlabel('球队',fontsize=20) #设置x轴标注为‘球队’,并调整字体大小 12 plt.ylabel('场均助攻',fontsize=20) #设置y轴标注为‘国内生产总值(亿元)’,并调整字体大小 13 plt.show()
1 X = df.排名 2 Y = df.抢断 3 def A(): 4 plt.scatter(X,Y,color="blue",linewidth=2) 5 plt.title("场均抢断的散点图",color="blue") 6 plt.grid() 7 plt.show() 8 def B(): 9 plt.scatter(X,Y,color="green",linewidth=2) 10 plt.title("redu",color="blue") 11 plt.grid() 12 plt.show() 13 def func(p,x): 14 a,b,c=p 15 return a*x*x+b*x+c 16 def error(p,x,y): 17 return func(p,x)-y 18 def main(): 19 plt.figure(figsize=(10,6)) 20 p0=[0,0,0] 21 Para = leastsq(error,p0,args=(X,Y)) 22 a,b,c=Para[0] 23 print("a=",a,"b=",b,"c=",c) 24 plt.scatter(X,Y,color="blue",linewidth=2) 25 x=np.linspace(0,20,20) 26 y=a*x*x+b*x+c 27 plt.plot(x,y,color="blue",linewidth=2,) 28 plt.title("场均抢断分布") 29 plt.grid() 30 plt.show() 31 print(A()) 32 print(B()) 33 print(main())
1 X = df.排名 2 Y = df.失误 3 def A(): 4 plt.scatter(X,Y,color="blue",linewidth=2) 5 plt.title("场均失误的散点图",color="blue") 6 plt.grid() 7 plt.show() 8 def B(): 9 plt.scatter(X,Y,color="green",linewidth=2) 10 plt.title("redu",color="blue") 11 plt.grid() 12 plt.show() 13 def func(p,x): 14 a,b,c=p 15 return a*x*x+b*x+c 16 def error(p,x,y): 17 return func(p,x)-y 18 def main(): 19 plt.figure(figsize=(10,6)) 20 p0=[0,0,0] 21 Para = leastsq(error,p0,args=(X,Y)) 22 a,b,c=Para[0] 23 print("a=",a,"b=",b,"c=",c) 24 plt.scatter(X,Y,color="blue",linewidth=2) 25 x=np.linspace(0,20,20) 26 y=a*x*x+b*x+c 27 plt.plot(x,y,color="blue",linewidth=2,) 28 plt.title("场均失误分布") 29 plt.grid() 30 plt.show() 31 print(A()) 32 print(B()) 33 print(main())
四、完整代码
1 import requests 2 from bs4 import BeautifulSoup 3 import json 4 r=requests.get('https://china.nba.cn/stats2/league/teamstats.json?conference=All&division=All&locale=zh_CN&season=2021&seasonType=2') 5 r.encoding="utf-8" 6 data=json.loads(r.text) 7 print(data) 8 b=data['payload']['teams'] 9 for i in b: 10 print(i) 11 name=[] 12 for i in b: 13 name.append(i['profile']['name']) 14 for i in b: 15 pointsPg.append(i['statAverage']['pointsPg']) 16 rebsPg=[] 17 for i in b: 18 rebsPg.append(i['statAverage']['rebsPg']) 19 games=[] 20 for i in b: 21 games.append(i['statAverage']['games']) 22 turnoversPg=[] 23 for i in b: 24 turnoversPg.append(i['statAverage']['turnoversPg']) 25 stealsPg=[] 26 for i in b: 27 stealsPg.append(i['statAverage']['stealsPg']) 28 assistsPg=[] 29 for i in b: 30 assistsPg.append(i['statAverage']['assistsPg']) 31 rank=[] 32 for i in range(1,31): 33 rank.append(i) 34 print(name) 35 print(pointsPg) 36 print(rebsPg) 37 print(games) 38 print(turnoversPg) 39 print(stealsPg) 40 print(assistsPg) 41 import pandas as pd 42 df=pd.DataFrame({'排名':rank, 43 '球队名':name, 44 '场均篮板':rebsPg, 45 '场数':games, 46 '失误':turnoversPg, 47 '抢断':stealsPg, 48 '场均助攻':assistsPg, 49 }) 50 df 51 df.to_csv('D:\python\球队数据.csv',index=False) 52 import matplotlib 53 chinese=matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\simsun.ttc') 54 import matplotlib as mpl 55 mpl.rcParams['font.sans-serif'] = ["SimHei"] 56 mpl.rcParams["axes.unicode_minus"] = False 57 import matplotlib.pyplot as plt 58 plt.figure(figsize=(10,6)) 59 x=rank[0:5] 60 x1=name[0:5] 61 a=['a','b','c'] 62 total_width,n=0.8,3 63 #设置间距 64 width=total_width/n 65 #在偏移间距位置绘制柱状图1 66 for i in range(len(x)): 67 x[i]-=width 68 plt.bar(x1,rebsPg[0:5],label='场均篮板',fc='teal') 69 #设置数字标签 70 for a,b in zip(x,rebsPg[0:5]): 71 plt.text(a,b,b,ha='center',va='bottom',fontsize=10) 72 #在偏移间距位置绘制柱状图2 73 for i in range(len(x)): 74 x[i]+=width 75 plt.bar(x,turnoversPg[0:5],label='失误',tick_label=name,fc='darkorange') 76 for a,b in zip(x1,turnoversPg[0:5]): 77 plt.text(a,b,b,ha='center',va='bottom',fontsize=10) 78 #在偏移间距位置绘制柱状图3 79 for i in range(len(x)): 80 x[i]+=width 81 plt.bar(x,assistsPg[0:5],label='场均助攻',fc='lightcoral') 82 for a,b in zip (x1,assistsPg[0:5]): 83 plt.text(a,b,b,ha='center',va='bottom',fontsize=10) 84 import seaborn as sns 85 sns.regplot(df['排名'],df['场均篮板']) 86 data=pd.Series(games[0:8],name[0:8]) 87 data.plot(kind='bar',title='场数') 88 plt.show() 89 import matplotlib.pyplot as plt 90 plt.rcParams['font.sans-serif']='SimHei'#设置中文显示 91 plt.figure(figsize=(6,6))#将画布设定为正方形,则绘制的饼图是正圆 92 label=name[0:5]#定义饼图的标签,标签是列表 93 explode=[0.01,0.01,0.01,0.01,0.01]#设定各项距离圆心n个半径 94 #plt.pie(values[-1,3:6],explode=explode,labels=label,autopct='%1.1f%%')#绘制饼图 95 values=turnoversPg[0:5] 96 plt.pie(values,explode=explode,labels=label,autopct='%1.1f%%')#绘制饼图 97 plt.title('排名前5的失误比例')#绘制标题 98 plt.savefig('./')#保存图片 99 plt.show() 100 #画出散点图 101 plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 102 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 103 N=10 104 x=np.random.rand(N) 105 y=np.random.rand(N) 106 size=50 107 plt.xlabel("排名") 108 plt.ylabel("热度") 109 plt.scatter(x,y,size,color='r',alpha=0.5,marker="o") 110 #散点图 kind='reg' 111 sns.jointplot(x="排名",y="失误",data=df,kind='reg') 112 # kind='hex' 113 sns.jointplot(x="排名",y="失误",data=df,kind='hex') 114 # kind='kde' 115 sns.jointplot(x="排名",y="失误",data=df,kind="kde",space=0,color='g') 116 data=pd.Series(stealsPg[0:8],name[0:8]) 117 data.plot(kind='bar',title='抢断') 118 plt.show() 119 import matplotlib.pyplot as plt 120 plt.rcParams['font.sans-serif']='SimHei'#设置中文显示 121 plt.figure(figsize=(6,6))#将画布设定为正方形,则绘制的饼图是正圆 122 label=name[25:30]#定义饼图的标签,标签是列表 123 explode=[0.01,0.01,0.01,0.01,0.01]#设定各项距离圆心n个半径 124 #plt.pie(values[-1,3:6],explode=explode,labels=label,autopct='%1.1f%%')#绘制饼图 125 values=turnoversPg[25:30] 126 plt.pie(values,explode=explode,labels=label,autopct='%1.1f%%')#绘制饼图 127 plt.title('排名后5名的失误比例')#绘制标题 128 plt.savefig('./')#保存图片 129 plt.show() 130 X = df.排名 131 Y = df.场均篮板 132 def A(): 133 plt.scatter(X,Y,color="blue",linewidth=2) 134 plt.title("场均篮板的散点图",color="blue") 135 plt.grid() 136 plt.show() 137 def B(): 138 plt.scatter(X,Y,color="green",linewidth=2) 139 plt.title("redu",color="blue") 140 plt.grid() 141 plt.show() 142 def func(p,x): 143 a,b,c=p 144 return a*x*x+b*x+c 145 def error(p,x,y): 146 return func(p,x)-y 147 def main(): 148 plt.figure(figsize=(10,6)) 149 p0=[0,0,0] 150 Para = leastsq(error,p0,args=(X,Y)) 151 a,b,c=Para[0] 152 print("a=",a,"b=",b,"c=",c) 153 plt.scatter(X,Y,color="blue",linewidth=2) 154 x=np.linspace(0,20,20) 155 y=a*x*x+b*x+c 156 plt.plot(x,y,color="blue",linewidth=2,) 157 plt.title("场均篮板数分布") 158 plt.grid() 159 plt.show() 160 print(A()) 161 print(B()) 162 print(main()) 163 #绘制“场均助攻”的直方图 164 import matplotlib.pyplot as plt 165 import pandas as pd 166 import numpy as np 167 plt.rcParams['font.sans-serif'] = ['KaiTi'] # 指定默认字体 168 plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题 169 df['场均助攻'].plot(kind='bar',figsize=(15,10)) 170 plt.suptitle('场均助攻',fontsize=20) 171 plt.xticks(fontsize=20) #修改x轴字体大小为20 172 plt.yticks(fontsize=20) #修改y轴字体大小为20 173 plt.xlabel('球队',fontsize=20) #设置x轴标注为‘球队’,并调整字体大小 174 plt.ylabel('场均助攻',fontsize=20) #设置y轴标注为‘国内生产总值(亿元)’,并调整字体大小 175 plt.show() 176 X = df.排名 177 Y = df.抢断 178 def A(): 179 plt.scatter(X,Y,color="blue",linewidth=2) 180 plt.title("场均抢断的散点图",color="blue") 181 plt.grid() 182 plt.show() 183 def B(): 184 plt.scatter(X,Y,color="green",linewidth=2) 185 plt.title("redu",color="blue") 186 plt.grid() 187 plt.show() 188 def func(p,x): 189 a,b,c=p 190 return a*x*x+b*x+c 191 def error(p,x,y): 192 return func(p,x)-y 193 def main(): 194 plt.figure(figsize=(10,6)) 195 p0=[0,0,0] 196 Para = leastsq(error,p0,args=(X,Y)) 197 a,b,c=Para[0] 198 print("a=",a,"b=",b,"c=",c) 199 plt.scatter(X,Y,color="blue",linewidth=2) 200 x=np.linspace(0,20,20) 201 y=a*x*x+b*x+c 202 plt.plot(x,y,color="blue",linewidth=2,) 203 plt.title("场均抢断分布") 204 plt.grid() 205 plt.show() 206 print(A()) 207 print(B()) 208 print(main()) 209 X = df.排名 210 Y = df.失误 211 def A(): 212 plt.scatter(X,Y,color="blue",linewidth=2) 213 plt.title("场均失误的散点图",color="blue") 214 plt.grid() 215 plt.show() 216 def B(): 217 plt.scatter(X,Y,color="green",linewidth=2) 218 plt.title("redu",color="blue") 219 plt.grid() 220 plt.show() 221 def func(p,x): 222 a,b,c=p 223 return a*x*x+b*x+c 224 def error(p,x,y): 225 return func(p,x)-y 226 def main(): 227 plt.figure(figsize=(10,6)) 228 p0=[0,0,0] 229 Para = leastsq(error,p0,args=(X,Y)) 230 a,b,c=Para[0] 231 print("a=",a,"b=",b,"c=",c) 232 plt.scatter(X,Y,color="blue",linewidth=2) 233 x=np.linspace(0,20,20) 234 y=a*x*x+b*x+c 235 plt.plot(x,y,color="blue",linewidth=2,) 236 plt.title("场均失误分布") 237 plt.grid() 238 plt.show() 239 print(A()) 240 print(B()) 241 print(main())
五、总结
1.经过对数据的分析和可视化,从回归方程和拟合曲线可以看出散点大部分都落在曲线上。
2.越靠前的球队篮板数和场均助攻越多。
3.各个球队的场均失误数差不多,说明场均失误对球队实力差距影响不大。
小结:在这次对NBA球队的分析的过程中,我从中学会了不少函数及用法。很多次都卡在一个点上,绞尽脑汁去想解决问题的办法,通过观看b站的视频,百度搜索等方法去找寻答案。这两个星期来也养成了耐心和独立思考的习惯,并且提高了我对Python的兴趣。