爬取奥运奖牌榜前20名

一、选题背景

我对于奥运会的奖牌数比较关注,可能是比较热爱运动带来的一种习惯,爬虫在python应用广泛,人人皆知,很适应于了解一些内容。2022年的奥运会也即将开始了,在社会上能够让人们快速地知道奖牌数的排行,经济上符合了当下的情景,网上的数据直观通俗易懂,也是人们常关注的平台。我的预期目标是爬取2008奥运奖牌榜的前十名次。

二、主题式网络爬虫设计方案

1.主题式网络爬虫名称

爬取2008奥运奖牌榜前二十名

2.主题式网络爬虫爬取的内容与数据特征分析

爬取内容:爬取网页排名,国家/地区总数

3.主题式网络爬虫设计方案概述

 

方案概述:访问网页得到状态码200,分析网页源代码,找出所需要的的标签,逐个提取标签保存到相同路径csv文件中,读取改文件,进行数据清洗,数据模型分析,数据可视化处理,绘制分布图,用最小二乘法分析两个变量间的二次拟合方程和绘制拟合曲线。

 

技术难点:做数据分析,即求回归系数,因为国家/地区是文字,无法与数字作比较,需要把国家/地区这一列删除才可。由于不明原因,输出结果经常会显示超出列表范围。

 三、主题页面的结构特征分析

1.主题页面的结构特征https://cq.qq.com/c/ayjpb/index.htm

 

通过开发人员选项查看它的第一行标题是独立出来的。第一行标签:’th.width’,剩余的行标签:’td.class’;但国家/地区这一列的标签有变化,它含有图片和中文:中文标签:span.class

 

2. 页面解析

 

 

 

 3.

F12 (右击检查)

使用鼠标进行滑动选择想找的   

控制键+上档键+c  

注:类似在电脑中打开某盘某文件夹查找某文件。

 四、

1.

 1 #获取html网页
 2 url = 'https://www.sogou.com/link?url=6YUuC6e6hWa2n28n1HKKbDfznB86Obg4_EP5ocOcjDS8H3hzb6JqFQ..'
 3 header={
 4     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
 5     'Referer': 'https://cq.qq.com/c/ayjpb/index.htm'}
 6 #请求超时时间为30秒
 7 r = requests.get(url,timeout = 30,headers=header)
 8 #如果状态码不是200,则引发日常
 9 r.raise_for_status()
10 #配置编码
11 r.encoding = r.apparent_encoding
12 #获取源代码
13 r.text
14 html=r.text
15 soup=BeautifulSoup(html,'html.parser')
16 title = soup.find_all('a', class_='list-title')
17 point = soup.find_all('span', class_='icon-rise')
18 print('{:^55}'.format('2008奥运奖牌榜'))
19 print('{:^44}\t{:^122}\t{:^120}'.format('排名', '国家/地区',’总数’))
20 num = 20
21 lst = []
22 for i in range(num):
23     print('{:^44}\t{:^122}\t{:^120}\t{:^120}\t{:^120}\t{:^120}\t{:^120}'.format(i+1, title[i].string, point[i].string))
24     lst.append([i+1,title[i].string,point[i].string])
25 df = pd.DataFrame(lst,columns=['排名','国家/地区',’总数’])
26 rank = r'rank.xlsx'
27 df.to_excel(rank)

 

 

 

 

 

 

 

 2.

1 #读取csv文件
2 rank=pd.DataFrame(pd.read_excel('rank.xlsx'))
3 print(rank.head())

 

 

 3.

1 #删除无效列
2 #rank.drop('国家/地区',axis=1,inplace=True)
3 #print(rank.head)

 

 

 

 

 4.

1 #检查是否有重复值
2 print(rank.duplicated())

 

 

 5.

1 #检查是否有空值
2 print(rank['总数'].isnull().value_counts())

 

 

 6.

1 #异常值处理
2 print(rank.describe())
3 #发现“热度”字段的最大值为4457381而平均值为1301384,假设异常值为4457381
4 print(top.replace([4457381,top['热度'].mean()]))

 

 

 

 7.

1 #数据分析
2 from sklearn.linear_model import LinearRegression
3 X = df.drop("国家/地区",axis=1)
4 predict_model = LinearRegression()
5 predict_model.fit(X,df['总数'])
6 print("回归系数为:",predict_model.coef_)

 

 

 

 8.

1 #绘制排名与热度的回归图
2 import seaborn as sns
3 sns.regplot(rank_df.排名,rank_df.总数)

 

 9.

 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=rank,kind='reg')
13 #  kind='hex'
14 sns.jointplot(x="排名",y="总数",data=rank,kind='hex')
15 # kind='kde'
16 sns.jointplot(x="排名",y="总数",data=rank,kind="kde",space=0,color='g')

 

 

 

 

 

 

 

 

 

 

     数据处理

 

 1 #声明x轴y轴的数据
 2 
 3     tGold = []
 4     tSilver = []
 5     tBronze = []
 6     tCountryName = []
 7 
 8     for i in Medallist:
 9         tGold.append(i['gold'])
10         tSilver.append(i['silver'])
11         tBronze.append(i['bronze'])
12         tCountryName.append(i['countryname'])
13 
14 #调用Pyecharts 生成条形图
15 
16 c = (
17         Bar(init_opts=opts.InitOpts(width='1440px',height='2000px'))
18             .add_yaxis("金牌", tGold, stack="stack1")
19             .add_yaxis("银牌", tSilver, stack="stack1")
20             .add_yaxis("铜牌", tBronze, stack="stack1")
21             .add_xaxis(tCountryName)
22             .reversal_axis()
23             .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
24             .set_global_opts(title_opts=opts.TitleOpts(title="2008奥运奖牌榜"),
25                              yaxis_opts=opts.AxisOpts(is_inverse=True)
26                              )
27     )
28     c.render("MedalList.html")

 

 

 

 10.

 1 #选择排名和总数两个特征变量,绘制分布图,用最小二乘法分析两个变量间的二次拟合方程和拟合曲线
 2 colnames=[" ","排名","国家/地区","总数"]
 3 df = pd.read_excel('rank.xlsx',skiprows=1,names=colnames)
 4 X = df.排名
 5 Y = df.总数
 6 Z = df.国家/地区
 7 def A():
 8     plt.scatter(X,Y,color="blue",linewidth=2)
 9     plt.title("RM scatter",color="blue")
10     plt.grid()
11     plt.show()
12 def B():
13     plt.scatter(X,Y,color="green",linewidth=2)
14     plt.title("redu",color="blue")
15     plt.grid()
16     plt.show()
17 def func(p,x):
18     a,b,c=p
19     return a*x*x+b*x+c
20 def error(p,x,y):
21     return func(p,x)-y
22 def main():
23     plt.figure(figsize=(10,6))
24     p0=[0,0,0]
25     Para = leastsq(error,p0,args=(X,Y))
26     a,b,c=Para[0]
27     print("a=",a,"b=",b,"c=",c)
28     plt.scatter(X,Y,color="blue",linewidth=2)
29     x=np.linspace(0,20,20)
30     y=a*x*x+b*x+c
31     plt.plot(x,y,color="blue",linewidth=2,)
32     plt.title("总数分布")
33     plt.grid()
34     plt.show()
35 print(A())
36 print(B())

 

 

 

 

 完整代码 

 

  1 #获取html网页
  2 url = 'https://www.sogou.com/linkurl=6YUuC6e6hWa2n28n1HKKbDfznB86Obg4_EP5ocOcjDS8H3hzb6JqFQ..'
  3 
  4 header={
  5 
  6     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
  7     'Referer': 'https://cq.qq.com/c/ayjpb/index.htm'}
  8 
  9 
 10 #请求超时时间为30秒
 11 
 12 
 13 r = requests.get(url,timeout = 30,headers=header)
 14 
 15 
 16 #如果状态码不是200,则引发日常
 17 
 18 
 19 r.raise_for_status()
 20 
 21 
 22 #配置编码
 23 
 24 
 25 r.encoding = r.apparent_encoding
 26 
 27 
 28 #获取源代码
 29 
 30 
 31 r.text
 32 
 33 html=r.text
 34 
 35 soup=BeautifulSoup(html,'html.parser')
 36 
 37 title = soup.find_all('a', class_='list-title')
 38 
 39 point = soup.find_all('span', class_='icon-rise')
 40 
 41 
 42 print('{:^55}'.format('2008奥运奖牌榜'))
 43 
 44 print('{:^44}\t{:^122}\t{:^120}'.format('排名', '国家/地区',’总数’))
 45 
 46 
 47 num = 20
 48 
 49 lst = []
 50 
 51 
 52 for i in range(num):
 53 
 54 
 55 
 56 print('{:^44}\t{:^122}\t{:^120}\t{:^120}\t{:^120}\t{:^120}\t{:^120}'.format(i+1, title[i].string, point[i].string))
 57 
 58     lst.append([i+1,title[i].string,point[i].string])
 59 
 60 df = pd.DataFrame(lst,columns=['排名','国家/地区',’总数’])
 61 
 62 rank = r'rank.xlsx'
 63 
 64 df.to_excel(rank)
 65 
 66 
 67 #读取csv文件
 68 
 69 
 70 rank=pd.DataFrame(pd.read_excel('rank.xlsx'))
 71 
 72 print(rank.head())
 73 
 74 
 75 #删除无效列
 76 
 77 
 78 rank.drop('国家/地区',axis=1,inplace=True)
 79 
 80 
 81 #print(rank.head)
 82 
 83 
 84 
 85 #检查是否有重复值
 86 
 87 
 88 print(rank.duplicated())
 89 
 90 #检查是否有空值
 91 
 92 
 93 print(rank['总数'].isnull().value_counts())
 94 
 95 
 96  #异常值处理
 97 
 98 
 99 print(rank.describe())
100 
101 
102 #发现“热度”字段的最大值为4457381而平均值为1301384,假设异常值为4457381
103 
104 
105 print(top.replace([4457381,top['热度'].mean()]))
106 
107 
108 
109 #数据分析
110 
111 
112 
113 from sklearn.linear_model import LinearRegression
114 
115 
116 X = df.drop("国家/地区",axis=1)
117 
118 
119 predict_model = LinearRegression()
120 
121 
122 predict_model.fit(X,df['总数'])
123 
124 
125 
126 print("回归系数为:",predict_model.coef_)
127 
128 
129 #绘制排名与热度的回归图
130 
131 
132 import seaborn as sns
133 
134 
135 sns.regplot(rank_df.排名,rank_df.总数)
136 
137 
138 #画出散点图
139 
140 
141 # 用来正常显示中文标签
142 
143 
144 plt.rcParams['font.sans-serif'] = ['SimHei']
145 
146 
147 # 用来正常显示负号
148 
149 
150 plt.rcParams['axes.unicode_minus'] = False
151 
152 
153 N=10
154 
155 
156 x=np.random.rand(N)
157 
158 
159 y=np.random.rand(N)
160 
161 
162 size=50
163 
164 
165 plt.xlabel("排名")
166 
167 
168 plt.ylabel("总数")
169 
170 
171 plt.scatter(x,y,size,color='r',alpha=0.5,marker="o")
172 
173 
174 
175 #散点图  kind='reg'
176 
177 
178 sns.jointplot(x="排名",y="总数",data=rank,kind='reg')
179 
180 
181 #  kind='hex'
182 
183 
184 sns.jointplot(x="排名",y="总数",data=rank,kind='hex')
185 
186 
187 # kind='kde'
188 
189 
190 sns.jointplot(x="排名",y="总数",data=rank,kind="kde",space=0,color='g')
191 
192 
193 
194 #声明x轴y轴的数据
195 
196     tGold = []
197 
198     tSilver = []
199 
200     tBronze = []
201 
202     tCountryName = []
203 
204 
205     for i in Medallist:
206 
207         tGold.append(i['gold'])
208 
209         tSilver.append(i['silver'])
210 
211         tBronze.append(i['bronze'])
212 
213         tCountryName.append(i['countryname'])
214 
215 #调用Pyecharts 生成条形图
216 
217 c = (
218 
219         Bar(init_opts=opts.InitOpts(width='1440px',height='2000px'))
220 
221             .add_yaxis("金牌", tGold, stack="stack1")
222 
223             .add_yaxis("银牌", tSilver, stack="stack1")
224 
225             .add_yaxis("铜牌", tBronze, stack="stack1")
226 
227             .add_xaxis(tCountryName)
228 
229             .reversal_axis()
230 
231             .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
232 
233             .set_global_opts(title_opts=opts.TitleOpts(title="2008奥运奖牌榜"),
234 
235                              yaxis_opts=opts.AxisOpts(is_inverse=True)
236 
237                              )
238     )
239 
240     c.render("MedalList.html")
241 
242 
243 #选择排名和总数两个特征变量,绘制分布图,用最小二乘法分析两个变量间的二次拟合方程和拟合曲线
244 
245 
246 colnames=[" ","排名","国家/地区","总数"]
247 
248 
249 df = pd.read_excel('rank.xlsx',skiprows=1,names=colnames)
250 
251 
252 X = df.排名
253 
254 
255 Y = df.总数
256 
257 
258 Z = df.国家/地区
259 
260 
261 def A():
262 
263 
264     plt.scatter(X,Y,color="blue",linewidth=2)
265 
266 
267     plt.title("RM scatter",color="blue")
268 
269 
270     plt.grid()
271 
272 
273     plt.show()
274 
275 
276 
277 def B():
278 
279 
280     plt.scatter(X,Y,color="green",linewidth=2)
281 
282 
283     plt.title("redu",color="blue")
284 
285 
286     plt.grid()
287 
288 
289     plt.show()
290 
291 
292 
293 def func(p,x):
294 
295 
296     a,b,c=p
297 
298 
299     return a*x*x+b*x+c
300 
301 
302 def error(p,x,y):
303 
304 
305     return func(p,x)-y
306 
307 
308 def main():
309 
310 
311     plt.figure(figsize=(10,6))
312 
313 
314     p0=[0,0,0]
315 
316 
317     Para = leastsq(error,p0,args=(X,Y))
318 
319 
320     a,b,c=Para[0]
321 
322 
323     print("a=",a,"b=",b,"c=",c)
324 
325 
326 
327     plt.scatter(X,Y,color="blue",linewidth=2)
328 
329 
330     x=np.linspace(0,20,20)
331 
332 
333     y=a*x*x+b*x+c
334 
335 
336     plt.plot(x,y,color="blue",linewidth=2,)
337 
338 
339     plt.title("总数分布")
340 
341 
342     plt.grid()
343 
344 
345     plt.show()
346 
347 
348 
349 print(A())
350 
351 
352 print(B())

 

 五、总结

1.暂时没有达到预期的目标;对于数据可视化的方面可能研究并没有这么透彻,可能时间有限,但以后有的是时间。

2.爬虫这方面我得多下点功夫,虽然这一次我没有学会爬虫,我会在以后的一段时间里多加练习,多参考网上的学习资源,在那些优秀博文上多多学习和模仿,做出属于我自己的爬虫python爬虫课程设计的一份完整作品。当然,向老师询问相关的知识也得频率多一些,这样才会有所进步,对于我自己的预想的目标才会有所进展。”失败是成功之母“,错了不可怕,能改回来才是对的。我相信我日后我可以持之以恒地投入到这方面中,让我自己能够优秀起来。

 

posted @ 2021-12-28 22:18  cody666  阅读(183)  评论(0编辑  收藏  举报