2022年卡塔尔世界杯正在如火如荼地进行着,看球时经常听到两队历史交锋数据,突发奇想,要不,用Python来爬一爬历史上所有世界杯的比赛结果,或许这些数据还能帮我们处理一些实际问题?(比如预测?。。)所以这篇文章就来演示一下,如何使用Python和BeautifulSoup来获取世界杯至今(1930-2018)包括当前正在进行的2022年所有比赛结果数据。
安装必要的开源库
这篇文章我们主要使用bs4来爬取网页,用lxml来解析HTML内容,然后使用requests来向目前网页发送请求。
在你的终端上执行以下命令,来安装这些pip包:
$ pip install bs4
$ pip install lxml
$ pip install requests
除了以上三个,我们还需要安装著名的pandas,用来做必要的数据解析:
$ pip install pandas
1. 获取2014年世界杯的数据
这篇文章分成两个部分,第一部分是爬取2014年巴西世界杯的数据,第二部分是把第一部分代码扩展后应用到自1930年开始的所有世界杯比赛数据上。有一点需要注意的是,由于我们将使用维基百科Wikipedia作为数据源,因此需要使python运行的环境有能力访问维基百科,可以使用vpn也可部署在国外服务器上运行,具体方法这里就不细述了。
导入第三方库
首先,导入我们之前安装的库,用以接下来调用。
import pandas as pd
from bs4 import BeautifulSoup
import requests
这里看到我们并不需要import lxml,因为在bs4的关联里已经包含了它。
创建一个Soup
为了能够调用BeautifulSoup,我们首先需要创建一个soup。soup使用lxml解析器来解析HTML的内容。
web = 'https://en.wikipedia.org/wiki/2014_FIFA_World_Cup'
response = requests.get(web)
content = response.text
soup = BeautifulSoup(content, 'lxml')
解析所有的比赛
首先我们要找到不单是一场比赛,而是找到当届世界杯所有比赛结果的网页展现模式。
最简单的方式,我们现在在浏览器里打开2014年世界杯的维基百科网页:
https://en.wikipedia.org/wiki/2014_FIFA_World_Cup
我们可以在网页上任意位置按鼠标右键,在菜单里选择“Inspect”或“检查”,之后浏览器的开发者工具就会显示出来,推荐Chrome或Firefox,工具的界面类似。然后找到以下这个箭头标志,点击它,触发鼠标跟随模式:
接着我们在网页上发现的一个如下模式:
可以明显看出,在网页上每一行所代表的一场比赛交锋都包含在图片中蓝色高亮的那条HTML节点之下。
现在我们来用soup中的.find_all方法,它需要两个输入参数:tag name和class name。
matches = soup.find_all('div', class_='footballbox')
通过这句代码我把所有的比赛场次所显示的行,都赋值给了matches。
解析主/客场球队名称和比赛
现在我们需要在matches列表里进行轮询,以解析出每场比赛的具体数据。具体在这篇文章里,我将只解析出双方队名和比分,把他们保存到一个空列表里,方便以后导出到外部表格里。
让我们先来获取主队(home)数据,还是使用网页inspect追踪到主队的名称位置,获取到它的tag name和class name。然后同样的操作在比分(score),以及客队(away)上重复一遍。
最后,我们用.get_text方法获取到这个类包含的text内容:
home = []
score = []
away = []
for match in matches:
home.append(match.find('th', class_='fhome').get_text())
score.append(match.find('th', class_='fscore').get_text())
away.append(match.find('th', class_='faway').get_text())
用DataFrame存储数据并导出成CSV文件
数据帧(DataFrame)是Python的pandas里好用的数据管理工具,我们为主队,客队和比分建立数据帧对象,此外我们还增加一列year,来代表比赛的年份。
dict_football = {'home': home, 'score': score, 'away': away}
df_football = pd.DataFrame(dict_football)
df_football['year'] = 2014
最后,我们用一句代码,把数据导出到CSV文件里:
df_football.to_csv("fifa_worldcup_historical_data.csv", index=False)
2. 获取所有世界杯比赛数据
在上一章节,我们成功爬取了单届世界杯的数据,通过这种方式,可以很快爬取到每届赛事的数据。首先,我们确认,维基百科的网页链接模式:
https://en.wikipedia.org/wiki/2014_FIFA_World_Cup
https://en.wikipedia.org/wiki/2018_FIFA_World_Cup
https://en.wikipedia.org/wiki/2022_FIFA_World_Cup
可以明显看出,唯一的不同只是URL上的年份,那对我们来说就可以把年份作为变量,赋值给web字符串:
web = f'https://en.wikipedia.org/wiki/{year}_FIFA_World_Cup'
那么接下来只要在代码里动态给year赋值,并循环获取每年的数据就可以了:
import pandas as pd
from bs4 import BeautifulSoup
import requests
def get_matches(year):
web = f'https://en.wikipedia.org/wiki/{year}_FIFA_World_Cup'
response = requests.get(web)
content = response.text
soup = BeautifulSoup(content, 'lxml')
matches = soup.find_all('div', class_='footballbox')
home = []
score = []
away = []
for match in matches:
home.append(match.find('th', class_='fhome').get_text())
score.append(match.find('th', class_='fscore').get_text())
away.append(match.find('th', class_='faway').get_text())
dict_football = {'home': home, 'score': score, 'away': away}
df_football = pd.DataFrame(dict_football)
df_football['year'] = year
return df_football
初始化years列表,所有年份的世界杯数据就都到手啦。
years = [1930, 1934, 1938, 1950, 1954, 1958, 1962, 1966, 1970, 1974,
1978, 1982, 1986, 1990, 1994, 1998, 2002, 2006, 2010, 2014,
2018]
# results: historical data
fifa = [get_matches(year) for year in years]
df_fifa = pd.concat(fifa, ignore_index=True)
df_fifa.to_csv("fifa_worldcup_historical_data.csv", index=False)
当然我们还可以爬取当前正在进行中的2022卡塔尔世界杯的更新数据
df_fixture = get_matches(2022)
df_fixture.to_csv('fifa_worldcup_fixture.csv', index=False)
好了,就这么简单,现在你的电脑里有两个CSV文件了,一个是保存了所有世界杯所有历史对战记录,另一个是2022卡塔尔世界杯当前的数据记录。未来,用同样可以加入更多的数据维度,做更多的相关性研究,或许可以做一个章鱼保罗级别的预测呢,有时间的话,世界杯结束前我会做一期关于用python在做预测的内容。有兴趣的话记得关注!