
英雄联盟亚运会
-
2023年2月21日发(作者:)Python爬取OPGG⾥英雄联盟位置排名数据,及其可视化
⼀、选题背景
近年来电⼦竞技在当今社会越来越来受欢迎,同时电⼦竞技也成了亚运会项⽬之⼀。英雄联盟便是奥运会上的项⽬类型之⼀,我国便曾在亚运会的
英雄联盟项⽬上拿下冠军。所以我便选择了,英雄联盟这个项⽬来作为我的设计⽬标。
⼆、主题式⽹络爬⾍设计⽅案
1.主题式⽹络爬⾍名称
OPGG⾥英雄联盟位置排名数据,及其可视化
2.主题式⽹络爬⾍爬取的内容与数据特征分析
爬取opgg中上单及射⼿的排名,名字,胜率,出场率,并对其进⾏分析。
3.主题式⽹络爬⾍设计⽅案概述
(1)实现思路
先对⽬标页⾯进⾏分析,利⽤urllib.爬⾍库和BeautifulSoup库进⾏爬取解析,后分别⽤BeautifulSoup和正则表达式,分别查找所需要的数据。
然后再保存为.csv⽂件,最后进⾏可视化分析。
(2)技术难点
request库出现问题,被迫学习使⽤t库,在编写re库的正则表达式中,发现⾃⼰熟练程度低,出错较多,在数据可视化上也出现了
忘记代码的问题。
三、主题页⾯的结构特征分析
1.主题页⾯的结构与特征分析
⾸先是本机的usr-agent查询,做准备
由⽹站界⾯可以看出,右侧有英雄的详细信息,以Garen为例,胜率为53.84%,选取率为16.99%,常⽤位置为上单。
页⾯解析
现对⽹页源代码进⾏分析
代码中共有5个tbody标签(tbody标签开头结尾均有”tbody”,故共有10个”tbody”),对字段内容分析,分别为上单、打野、中单、ADC、辅助信
息。
再对tbody标签进⾏查找
由此代码可看出,英雄名、胜率及选取率都在td标签中,⽽每⼀个英雄信息在⼀个tr标签中,td⽗标签为tr标签,tr⽗标签为tbody标签
3.节点(标签)查找⽅法与遍历⽅法
计划将Beautifulsoup查找,re库.正则表达式搭配查找
四、⽹络爬⾍程序设计
1.数据爬取与采集
1defaskurl(urlbase):
t引⽤t库
3#模拟浏览器头部信息,向⽹站发送信息
4header={
5\"User-Agent\":\"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/96.0.4664.110Safari/537.36Edg/96.0.1054.62\"
6}
7#模拟⽤户代理
8request=t(urlbase,headers=header)
9#异常超时处理
10try:
11#html=\"\"
12response=n(request,timeout=5)
13html=().decode(\"utf-8\")
14#print(html)
15exceptExceptionasa:
16print(a)
17returnhtml
2.数据解析与整理
(1)采⽤BeautifulSoup解析提取数据
1importpandasaspd#导⼊pandas库
2importbs4#导⼊bs4库
3frombs4importBeautifulSoup#导⼊BeautifulSoup库
4url=\"/champion/statistics\"
5#获得html⽂档信息
6html=askurl(url)
7#解析数据
8soup=BeautifulSoup(html,\"\")
9top=[]
10name=[]#建⽴空列表⽤于储存数据
11winRate=[]
12pickRate=[]
13#遍历上单tbody标签的⼉⼦标签
(name=\"tbody\",attrs=\"tabItemchampion-trend-tier-TOP\").children:
15#判断tr是否为标签类型,去除空⾏
16ifisinstance(tr,):
17#查找tr标签下的td标签
18tds=tr(\'td\')
19#排名
(tds[0].string)
21#英雄名
(tds[3].find(attrs=\"champion-index-table__name\").string)
23#胜率%百分号对后续有影响,去除
(tds[4].e(\'%\',\'\'))
25#选取率
(tds[5].e(\'%\',\'\'))
27
28#将准确获得的数据保存到列表中
29df1=ame(data=[top,name,winRate,pickRate],index=[\'排名\',\'英雄名\',\'英雄胜率\',\'英雄出场率\'])
30#对⽂本进⾏,⾏换列,列换⾏
31df2=ame(.T,columns=)
32#保存数据到xlsx⽂件中
_excel(\'上单\')
(2)利⽤正则提取法提取数据
1frombs4importBeautifulSoup
2importre
3importpandasaspd
4ADtop=[]
5ADname=[]#设⽴空表格
6ADwinrate=[]
7ADpickrate=[]
8url=\"/champion/statistics\"
9#获得html⽂档信息
10html=askurl(url)
11#解析数据
12soup=BeautifulSoup(html,\"\")
13#取得射⼿标签内容
14ADCdata=_all(\"tbody\",class_=\"tabItemchampion-trend-tier-ADC\")
15#将BeautifulSoup类型转换为字符串类型,以便使⽤re库下的正则搜索
16strADCdata=str(ADCdata)
17#通过⽹页源码得知,需要收集的排名,英雄名信息为23条
18foriinrange(0,23):
19#排名设定约束
20findTop=e(r\'(d*?)\')
21#运⽤约束查找
(l(findTop,strADCdata)[i])
23#英雄名字设定约束
24findName=e(r\'(.*?)\')
25#运⽤约束查找
(l(findName,strADCdata)[i])
27#运⽤正则表达式查找时发现胜率与选取率除了标签,内容完全相同,导致在上⾯的循环中会出现交叉获得的问题出现。
28foriinrange(0,46,2):
29#英雄胜率设定约束获得偶数的胜率
30findWin=e(
31r\'(d{0,3}.d{2})%\')
(l(findWin,strADCdata)[i])
33#英雄出场率设定约束获得奇数的出场率
34findappear=e(
35r\'(d{0,3}.d{2})%
(l(findappear,strADCdata)[i+1])
37
38#将数据保存到列表中
39df3=ame(data=[ADtop,ADname,ADwinrate,ADpickrate],index=[\'排名\',\'英雄名\',\'英雄胜率\',\'英雄出场率\'])
40#对⽂本进⾏,⾏换列,列换⾏
41df4=ame(.T,columns=)
42#保存数据到xlsx⽂件中
_excel(\'射⼿\')
3.对数据进⾏清洗和处理
TOPrank=ame(_excel(\'上单\'))
print(())
##⽆⽆效列
#检查是否有重复值
print(ated())
#检查是否有空值
print(TOPrank[\'排名\'].isnull().value_counts())
#异常值处理
print(be())
#发现“排名”字段的最⼤值为56⽽平均值为28,假设异常值为56
#print(e([56,top[\'排名\'].mean()]))
4.数据分析与可视化
1:运⽤pyecharts制作表格视图
1importpandasaspd
entsimportTable
simportComponentTitleOpts
4
5#分别导⼊上单数据
6df_top=_excel(\'上单\')
7TOPTop=df_top[\'排名\'].()
8TOPName=df_top[\'英雄名\'].()
9TOPWin=df_top[\'英雄胜率\'].()
10TOPpick=df_top[\'英雄出场率\'].()
11
12#绘制上单表格视图
13table2=Table()
14headers2=[\"排名\",\"英雄名\",\"英雄胜率\",\"英雄出场率\"]
15rows2=[
16
17]
18foriinrange(0,56):
(df_[i].()[1:])#转换插⼊格式
(headers2,rows2)#插⼊数据
_global_opts(
22title_opts=ComponentTitleOpts(title=\"上单-强度排⾏\",subtitle=\"实时更新\")#设置标题与副标题
23)
(\"上单pyecharts表格.html\")
2:运⽤pyecharts制作柱状图
1importpandasaspd
importBar
simportThemeType
simportglobal_optionsasopts
5
6#分别导⼊上单数据
7df_top=_excel(\'上单\')
8TOPTop=df_top[\'排名\'].()
9TOPName=df_top[\'英雄名\'].()
10TOPWin=df_top[\'英雄胜率\'].()
11TOPpick=df_top[\'英雄出场率\'].()
12
13#绘制上单柱状图
14c=(
15Bar({\"theme\":NS})
_xaxis(TOPName)#设置x轴
_yaxis(\"英雄胜率\",TOPWin)#添加柱状体
_yaxis(\"英雄出场率\",TOPpick)
_global_opts(
20title_opts={\"text\":\"上单强度-⽰意图\",\"subtext\":\"综合胜率与出场率\"},#设置标题与副标题
21datazoom_opts=omOpts(),#分段
22xaxis_opts=ts(name_rotate=60,name=\"英雄名\",axislabel_opts={\"rotate\":35})#字体倾斜⾓度
23
24)
(\"上单强度柱状图.html\")
26)
3:运⽤pyecharts制作折线图
1importpandasaspd
sasopts
importLine
4#分别导⼊上单数据
5df_top=_excel(\'上单\')
6TOPTop=df_top[\'排名\'].()
7TOPName=df_top[\'英雄名\'].()
8TOPWin=df_top[\'英雄胜率\'].()
9TOPpick=df_top[\'英雄出场率\'].()
10(
11Line()
_global_opts(
13tooltip_opts=pOpts(is_show=False),
14xaxis_opts=ts(type_=\"category\"),
15yaxis_opts=ts(
16type_=\"value\",
17axistick_opts=ckOpts(is_show=True),
18splitline_opts=ineOpts(is_show=True),
19),
20)
_xaxis(xaxis_data=TOPName)
_yaxis(
23series_name=\"\",
24y_axis=TOPWin,
25symbol=\"emptyCircle\",
26is_symbol_show=True,
27label_opts=pts(is_show=False),
28)
_global_opts(
30title_opts={\"text\":\"上单英雄-对应胜率曲线\",\"subtext\":\"强度曲线\"},
31datazoom_opts=omOpts(),#分段
32xaxis_opts=ts(name_rotate=60,name=\"英雄名\",axislabel_opts={\"rotate\":35})#字体倾斜⾓度
33)
(\"上单胜率折线图.html\")
35)
5.完整代码
1#-*-coding=utf-8-*-
2#@Time:2021/12/2414:49
3#@Author:真建彬
4#@StudentNumber:2003010221
5#@File:
6
7defaskurl(urlbase):
t
9#模拟浏览器头部信息,向⽹站发送信息
10header={
11\"User-Agent\":\"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/96.0.4664.110Safari/537.36Edg/96.0.1054.62\"
12}
13#模拟⽤户代理
14request=t(urlbase,headers=header)
15#异常超时处理
16try:
17#html=\"\"
18response=n(request,timeout=5)
19html=().decode(\"utf-8\")
20#print(html)
21exceptExceptionasa:
22print(a)
23returnhtml
24
25defmain():
importBar
simportThemeType
28importre
29importpandasaspd
30importbs4#导⼊bs4库
31frombs4importBeautifulSoup#导⼊BeautifulSoup库
sasopts
importLine
entsimportTable
simportComponentTitleOpts
36url=\"/champion/statistics\"
37#获得html⽂档信息
38html=askurl(url)
39#解析数据
40soup=BeautifulSoup(html,\"\")
41top=[]
42name=[]#建⽴空列表⽤于储存数据
43winRate=[]
44pickRate=[]
45#遍历上单tbody标签的⼉⼦标签
(name=\"tbody\",attrs=\"tabItemchampion-trend-tier-TOP\").children:
47#判断tr是否为标签类型,去除空⾏
48ifisinstance(tr,):
49#查找tr标签下的td标签
50tds=tr(\'td\')
51#排名
(tds[0].string)
53#英雄名
(tds[3].find(attrs=\"champion-index-table__name\").string)
55#胜率%百分号对后续有影响,去除
(tds[4].e(\'%\',\'\'))
57#选取率
(tds[5].e(\'%\',\'\'))
59
60#将准确获得的数据保存到列表中
61df1=ame(data=[top,name,winRate,pickRate],index=[\'排名\',\'英雄名\',\'英雄胜率\',\'英雄出场率\'])
62#对⽂本进⾏,⾏换列,列换⾏
63df2=ame(.T,columns=)
64#保存数据到xlsx⽂件中
_excel(\'上单\')
66##读取⽂件
67TOPrank=ame(_excel(\'上单\'))
68print(())
69
70##⽆⽆效列
71
72#检查是否有重复值
73print(ated())
74
75#检查是否有空值
76print(TOPrank[\'排名\'].isnull().value_counts())
77
78#异常值处理
79print(be())
80#发现“排名”字段的最⼤值为56⽽平均值为28,假设异常值为56
81#print(e([56,top[\'排名\'].mean()]))
82
83
84
85ADtop=[]
86ADname=[]#设⽴空表格
87ADwinrate=[]
88ADpickrate=[]
89#取得射⼿标签内容
90ADCdata=_all(\"tbody\",class_=\"tabItemchampion-trend-tier-ADC\")
91#将BeautifulSoup类型转换为字符串类型,以便使⽤re库下的正则搜索
92strADCdata=str(ADCdata)
93#通过⽹页源码得知,需要收集的排名,英雄名信息为23条
94foriinrange(0,23):
95#排名设定约束
96findTop=e(r\'(d*?)\')
97#运⽤约束查找
(l(findTop,strADCdata)[i])
99#英雄名字设定约束
100findName=e(r\'(.*?)\')
101#运⽤约束查找
(l(findName,strADCdata)[i])
103#运⽤正则表达式查找时发现胜率与选取率除了标签,内容完全相同,导致在上⾯的循环中会出现交叉获得的问题出现。
104foriinrange(0,46,2):
105#英雄胜率设定约束获得偶数的胜率
106findWin=e(r\'(d{0,3}.d{2})%\')
(l(findWin,strADCdata)[i])
108#英雄出场率设定约束获得奇数的出场率
109findappear=e(r\'(d{0,3}.d{2})%
(l(findappear,strADCdata)[i+1])
111
112#将数据保存到列表中
113df3=ame(data=[ADtop,ADname,ADwinrate,ADpickrate],index=[\'排名\',\'英雄名\',\'英雄胜率\',\'英雄出场率\'])
114#对⽂本进⾏,⾏换列,列换⾏
115df4=ame(.T,columns=)
116#保存数据到xlsx⽂件中
_excel(\'射⼿\')
118
119ADCrank=ame(_excel(\'射⼿\'))
120print(())
121
122##⽆⽆效列
123
124#检查是否有重复值
125print(ated())
126
127#检查是否有空值
128print(ADCrank[\'排名\'].isnull().value_counts())
129
130#异常值处理
131print(be())
132#发现“排名”字段的最⼤值为23⽽平均值为12,假设异常值为23
133#print(e([23,top2[\'排名\'].mean()]))
134
135#数据可视化:
136
137
138#分别导⼊射⼿数据
139df_ADC=_excel(\'射⼿\')
140ADCTop=df_ADC[\'排名\'].()
141ADCName=df_ADC[\'英雄名\'].()
142ADCWin=df_ADC[\'英雄胜率\'].()
143ADCpick=df_ADC[\'英雄出场率\'].()
144
145#分别导⼊上单数据
146df_top=_excel(\'上单\')
147TOPTop=df_top[\'排名\'].()
148TOPName=df_top[\'英雄名\'].()
149TOPWin=df_top[\'英雄胜率\'].()
150TOPpick=df_top[\'英雄出场率\'].()
151
152#利⽤pyecharts做表格视图
153
154#绘制射⼿表格视图
155table1=Table()
156headers1=[\"排名\",\"英雄名\",\"英雄胜率\",\"英雄出场率\"]#设置表头
157rows1=[
158
159]
160foriinrange(0,23):
(df_[i].()[1:])#转换插⼊格式
(headers1,rows1)#插⼊数据
_global_opts(
164title_opts=ComponentTitleOpts(title=\"射⼿-强度排⾏\",subtitle=\"实时更新\")#设置标题与副标题
165)
(\"射⼿pyecharts表格.html\")
167
168
169#绘制上单表格视图
170table2=Table()
171headers2=[\"排名\",\"英雄名\",\"英雄胜率\",\"英雄出场率\"]
172rows2=[
173
174]
175foriinrange(0,56):
(df_[i].()[1:])#转换插⼊格式
(headers2,rows2)#插⼊数据
_global_opts(
179title_opts=ComponentTitleOpts(title=\"上单-强度排⾏\",subtitle=\"实时更新\")#设置标题与副标题
180)
(\"上单pyecharts表格.html\")#记录
182
183#利⽤pyecharts绘制柱状图
184
185#绘制射⼿柱状图
186c=(
187Bar({\"theme\":NS})
_xaxis(ADCName)#设置x轴
_yaxis(\"英雄胜率\",ADCWin)#添加柱状体
_yaxis(\"英雄出场率\",ADCpick)
_global_opts(
192title_opts={\"text\":\"射⼿强度-⽰意图\",\"subtext\":\"综合胜率与出场率\"},#设置标题与副标题
193datazoom_opts=omOpts(),#分段
194xaxis_opts=ts(name_rotate=60,name=\"英雄名\",axislabel_opts={\"rotate\":35})#字体倾斜⾓度
195
196)
(\"ADC强度柱状图.html\")
198)
199#绘制上单柱状图
200c=(
201Bar({\"theme\":NS})
_xaxis(TOPName)#设置x轴
_yaxis(\"英雄胜率\",TOPWin)#添加柱状体
_yaxis(\"英雄出场率\",TOPpick)
_global_opts(
206title_opts={\"text\":\"上单强度-⽰意图\",\"subtext\":\"综合胜率与出场率\"},#设置标题与副标题
207datazoom_opts=omOpts(),#分段
208xaxis_opts=ts(name_rotate=60,name=\"英雄名\",axislabel_opts={\"rotate\":35})#字体倾斜⾓度
209
210)
(\"上单强度柱状图.html\")
212)
213
214
215#利⽤pyecharts绘制折线图:
216
217#绘制射⼿折线图
218(
219Line()
_global_opts(
221tooltip_opts=pOpts(is_show=False),
222xaxis_opts=ts(type_=\"category\"),
223yaxis_opts=ts(
224type_=\"value\",
225axistick_opts=ckOpts(is_show=True),
226splitline_opts=ineOpts(is_show=True),
227),
228)
_xaxis(xaxis_data=ADCName)
_yaxis(
231series_name=\"\",
232y_axis=ADCWin,
233symbol=\"emptyCircle\",
234is_symbol_show=True,
235label_opts=pts(is_show=False),
236)
_global_opts(
238title_opts={\"text\":\"射⼿英雄-对应胜率曲线\",\"subtext\":\"强度曲线\"},
239datazoom_opts=omOpts(),#分段
240xaxis_opts=ts(name_rotate=60,name=\"英雄名\",axislabel_opts={\"rotate\":35})#字体倾斜⾓度
241
242)
(\"ADC胜率折线图.html\")
244)
245
246#绘制上单折线图
247(
248Line()
_global_opts(
250tooltip_opts=pOpts(is_show=False),
251xaxis_opts=ts(type_=\"category\"),
252yaxis_opts=ts(
253type_=\"value\",
254axistick_opts=ckOpts(is_show=True),
255splitline_opts=ineOpts(is_show=True),
256),
257)
_xaxis(xaxis_data=TOPName)
_yaxis(
260series_name=\"\",
261y_axis=TOPWin,
262symbol=\"emptyCircle\",
263is_symbol_show=True,
264label_opts=pts(is_show=False),
265)
_global_opts(
267title_opts={\"text\":\"上单英雄-对应胜率曲线\",\"subtext\":\"强度曲线\"},
268datazoom_opts=omOpts(),#分段
269xaxis_opts=ts(name_rotate=60,name=\"英雄名\",axislabel_opts={\"rotate\":35})#字体倾斜⾓度
270
271)
(\"上单胜率折线图.html\")
273)
274
275
276
277
278
279#调⽤主函数
280if__name__==\"__main__\":
281main()
282print(\'程序运⾏成功\')
五、总结
1.经过对主题数据的分析与可视化,可以得到哪些结论?是否达到预期的⽬标?
结论:
(1)游戏⾥英雄强度强,并不代表着⾼选取率⾼胜率的结果。
(2)获取和处理数据上我巩固了许多知识,使运⽤他们变得更加熟悉。
达到了预期的⽬标。
2.在完成此设计过程中,得到哪些收获?以及要改进的建议?
收获:熟练了爬⾍的操作,且能更好的运⽤正则表达式
建议:有很多⼩细节卡了我很久,还是需要稳固基础。