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的兴趣。