使用Python机器学习预测足球比赛结果:第一篇 数据采集 (下)

利物浦7比0狂胜曼联,这个锅不能再让C罗背了吧。预测足球比分有什么好方法吗?

微信搜索关注《Python学研大本营》,加入读者群,分享更多精彩

探索足球结果和赔率的 Python 项目。

那么,让我们按照我所遵循的步骤进行:

Old Matches Scraper

在比赛页面中,到达指定日期

yearNow, monthNow, dayNow = self._getDate(day)
urlDay = self.originLink + "/en/matches/{year}-{month}-{day}".format(year=yearNow, month=monthNow, day=dayNow)
print(urlDay)
html = urlopen(urlDay)
bs = BeautifulSoup(html.read(), 'html.parser')def _getDate(self, date):"""Helper function used to format url in the desired date in getMatches():param date: datetime.date object:return: The formatted year, month and day of the date object"""year = str(date.year)month = str(date.month) if date.month >= 10 else '0' + str(date.month)day = str(date.day) if date.day >= 10 else '0' + str(date.day)return year, month, day

这个过程和下面的所有过程都是在用户定义的迭代宇宙中每天进行的。函数 getMatches() 有一个开始日期和一个结束日期,它设置了抓取器将执行的边界。

2.获取每张冠军表

championshipTables = bs.find_all('div', {'class':'table_wrapper'})
errorList = []
for i in range(len(championshipTables)):try:championshipTables[i].find('a', {'href':re.compile('^/en/comps/')}).get_text()except AttributeError:errorList.append(i)for error in errorList:del championshipTables[error]desiredTables = [ch for ch in championshipTables if ch.find('a', {'href':re.compile('^/en/comps/')}).get_text() in leagues]

按照第一步的例子,联赛变量可以由用户输入,所以他选择他想要报废的联赛。我们还可以在代码中看到一个 try-except 子句,它处理结构错误,例如网站中可能出现的假表。

3.从每个冠军表中,从比赛行中获取信息

for table in desiredTables:time.sleep(4)matchesLinks = []homeTeams = table.find_all('td', {'data-stat':'home_team'})for team in homeTeams:self.homeTeams.append(team.get_text())self.dates.append(day)awayTeams = table.find_all('td', {'data-stat':'away_team'})for team in awayTeams:self.awayTeams.append(team.get_text())scores = table.find_all('td', {'data-stat':'score'})for score in scores:scoreHome, scoreAway = self._getScore(score.get_text())self.scoresHome.append(scoreHome)self.scoresAway.append(scoreAway)matchesLinks.append(score.find('a', {'href':re.compile('^/')})['href'])if table.find_all('td', {'data-stat':'home_xg'}):homeXG = table.find_all('td', {'data-stat':'home_xg'})awayXG = table.find_all('td', {'data-stat':'away_xg'})for xg in homeXG:self.homeXG.append(xg.get_text())for xg in awayXG:self.awayXG.append(xg.get_text())else:for team in homeTeams:self.homeXG.append(np.nan)self.awayXG.append(np.nan)

在这里,除了在我们的列表中添加我们最开始想要的信息外,我突出显示了睡眠时间,用于控制我们在一定时间内发出的请求数量,避免我们的IP被禁止。另外值得注意的是每个比赛报告链接的存储,它包含在分数变量中。通过从分数变量而不是“匹配报告”中捕获链接,我们可以避免在内存中存储延迟或取消的匹配链接。这引导我们进入下一步:

4.获取每场比赛报告并检索信息

for link in matchesLinks:dfMatchStats.loc[len(dfMatchStats)] = self._getMatchStats(link)def _getMatchStats(self, url):"""Helper function to extract the match stats for each match in getMatches():param url: The match report url - is extracted in getMatches():return: List with match stats"""stats={"Fouls":[np.nan, np.nan], "Corners":[np.nan, np.nan], "Crosses":[np.nan, np.nan], "Touches":[np.nan, np.nan],"Tackles":[np.nan, np.nan], "Interceptions":[np.nan, np.nan],"Aerials Won":[np.nan, np.nan],"Clearances":[np.nan, np.nan], "Offsides":[np.nan, np.nan], "Goal Kicks":[np.nan, np.nan], "Throw Ins":[np.nan, np.nan],"Long Balls":[np.nan, np.nan]}matchStatsList = []htmlMatch = urlopen(self.originLink + url)bsMatch = BeautifulSoup(htmlMatch.read(), 'html.parser')homeLineup = bsMatch.find('div', {'class':'lineup', 'id':'a'})if not homeLineup:homePlayers = []awayPlayers = []for i in range(0,11):homePlayers.append(np.nan)awayPlayers.append(np.nan)yellowCardsHome = np.nanredCardsHome = np.nanyellowCardsAway = np.nanredCardsAway = np.nanmatchStatsList.extend([yellowCardsHome, redCardsHome, yellowCardsAway, redCardsAway])for key, value in stats.items():matchStatsList.extend(value)return homePlayers + awayPlayers + matchStatsListhomePlayers = homeLineup.find_all('a', {'href':re.compile('^/en/players')})[0:11]homePlayers = [player.get_text() for player in homePlayers]awayLineup = bsMatch.find('div', {'class':'lineup', 'id':'b'})awayPlayers = awayLineup.find_all('a', {'href':re.compile('^/en/players')})[0:11]awayPlayers = [player.get_text() for player in awayPlayers]matchCards = bsMatch.find_all('div', {'class':'cards'})yellowCardsHome = len(matchCards[0].find_all('span', {'class':'yellow_card'})) + len(matchCards[0].find_all('span', {'class':'yellow_red_card'}))redCardsHome = len(matchCards[0].find_all('span', {'class':'red_card'})) + len(matchCards[0].find_all('span', {'class':'yellow_red_card'}))yellowCardsAway = len(matchCards[1].find_all('span', {'class':'yellow_card'})) + len(matchCards[1].find_all('span', {'class':'yellow_red_card'}))redCardsAway = len(matchCards[1].find_all('span', {'class':'red_card'})) + len(matchCards[1].find_all('span', {'class':'yellow_red_card'}))matchStatsList.extend([yellowCardsHome, redCardsHome, yellowCardsAway, redCardsAway])extraStatsPanel = bsMatch.find("div", {"id":"team_stats_extra"})for statColumn in extraStatsPanel.find_all("div", recursive=False):column = statColumn.find_all("div")columnValues = [value.get_text() for value in column]for index, value in enumerate(columnValues):if not value.isdigit() and value in stats:stats[value] = [int(columnValues[index-1]), int(columnValues[index+1])]for key, value in stats.items():matchStatsList.extend(value)return homePlayers + awayPlayers + matchStatsList

正如您所看到的,这个过程有点棘手,所以让我们做一个简单的解释。黄色和红色卡片是通过将黄色或红色类别的卡片对象的数量相加而得出的。其他统计数据来自:

  • 检查预期统计数据字典中的统计数据

  • 如果为真,则使用链接到该统计的值更新字典,这些值是与统计名称相关的上一个和下一个值 热切的读者可能已经意识到第 2 步——获取每个冠军表——不是强制性的,但它使我们能够灵活地只过滤我们想要的联赛的比赛,这就是我采用的方法。

作为一个额外的步骤,我意识到需要创建一个检查点触发器,因为爬虫可能会面临无法预料的错误,或者 fbref 可能会不允许您的 IP 发出新请求,而这种情况将意味着大量时间的浪费。然后,每个月的每个第一天,我们都会保存到目前为止的爬虫工作,以防万一发生意外错误,我们有一个安全检查点可以检索。

仅此而已。在下面代码的底部,您可以看到日期更新 iteraroe 和格式化最终数据框所需的操作。

if day.day == 1:# if the process crashes, we have a checkpoint every month starterdfCheckpoint = dfMatchStats.copy()dfCheckpoint["homeTeam"] = self.homeTeamsdfCheckpoint["awayTeam"] = self.awayTeamsdfCheckpoint["scoreHome"] = self.scoresHomedfCheckpoint["scoreAway"] = self.scoresAway]dfCheckpoint["homeXG"] = self.homeXGdfCheckpoint["awayXG"] = self.awayXGdfCheckpoint["date"] = self.datesdfCheckpoint.to_pickle(os.path.join(self.dataFolder, 'checkPoint.pkl'))day = day + timedelta(days=1)
dfMatchStats["homeTeam"] = self.homeTeams
dfMatchStats["awayTeam"] = self.awayTeams
dfMatchStats["scoreHome"] = self.scoresHome
dfMatchStats["scoreAway"] = self.scoresAway
dfMatchStats["homeXG"] = self.homeXG
dfMatchStats["awayXG"] = self.awayXG
dfMatchStats["date"] = self.datesreturn dfMatchStats

数据框预览

整个过程允许我们抓取一些数据来建立模型来预测足球比赛,但我们仍然需要抓取有关即将举行的比赛的数据,以便我们可以对已经收集的数据做一些有用的事情。我为此找到的最佳来源是SofaScore,该应用程序还收集和存储有关比赛和球员的信息,但不仅如此,它们还在Bet365中提供每场比赛的实际赔率。

SofaScore 特别处理 JavaScript 代码,这意味着 html 脚本并不完全可供我们与 BeautifulSoup 一起使用。这意味着我们需要使用另一个框架来抓取他们的信息。我选择了广泛使用的Selenium包,它使我们能够像人类用户一样通过 Python 代码上网冲浪。您实际上可以看到网络驱动程序在您选择的浏览器中点击和导航——我选择了 Chrome。

在下图中,您可以看到 SofaScore 主页以及正在进行或即将进行的比赛,在右侧,您可以看到当您点击特定比赛然后点击“LINEUPS”时会发生什么。

SofaScore 界面

使用 Selenium,正如我所解释的,它的工作方式就像人类用户在网上冲浪一样,您可能会认为这个过程会慢一点,这是事实。因此,我们必须在每个步骤中更加小心,这样我们就不会点击不存在的按钮,一旦 JavaScript 代码仅在用户执行某些操作后呈现,例如当我们点击特定匹配项时,服务器会采取需要一些时间来渲染我们在第二张图片中看到的侧边菜单,如果代码在此期间尝试单击阵容按钮,则会返回错误。现在,让我们来看看代码。

即将到来的Matches Scraper

  1. 打开主页并激活“显示赔率”按钮

def _getDriver(self, path='D:/chromedriver_win32/chromedriver.exe'):chrome_options = Options()return webdriver.Chrome(executable_path=path, options=chrome_options)  def getMatchesToday(self):self.driver = self._getDriver(path=self.path)self.driver.get("https://www.sofascore.com/")WebDriverWait(self.driver, 20).until(EC.element_to_be_clickable((By.CLASS_NAME, "slider")))oddsButton = self.driver.find_element(By.CLASS_NAME, "slider")oddsButton.click()homeTeam=[]awayTeam=[]odds=[]homeOdds = []drawOdds = []awayOdds = []

正如我提到的,在启动驱动程序并到达 SofaScore 的 URL 后,我们需要等到赔率按钮呈现后才能单击它。我们还为我们创建了列表来存储抓取的信息。

2.店铺匹配主要信息

WebDriverWait(self.driver, 5).until(EC.visibility_of_element_located((By.CLASS_NAME, 'fvgWCd')))
matches = self.driver.find_elements(By.CLASS_NAME, 'js-list-cell-target')
for match in matches:if self._checkExistsByClass('blXay'):homeTeam.append(match.find_element(By.CLASS_NAME, 'blXay').text)awayTeam.append(match.find_element(By.CLASS_NAME, 'crsngN').text)if match.find_element(By.CLASS_NAME, 'haEAMa').text == '-':oddsObject = match.find_elements(By.CLASS_NAME, 'fvgWCd')for odd in oddsObject:odds.append(odd.text)while(len(odds) > 0):homeOdds.append(odds.pop(0))drawOdds.append(odds.pop(0))awayOdds.append(odds.pop(0))

这里没有什么特别的,但是考虑到在第 8 行我们只过滤还没有开始的匹配是很好的。我这样做是因为处理正在进行的比赛会使赔率变得更加棘手,而且目前还不清楚未来的投注模拟器将如何工作,而且它可能无法在实时结果中正常工作。

3.获得阵容

df = pd.DataFrame({"homeTeam":homeTeam, "awayTeam":awayTeam, "homeOdds":homeOdds, "drawOdds":drawOdds, "awayOdds":awayOdds})
lineups = self._getLineups()df = pd.concat([df, lineups], axis=1).iloc[:,:-1]return dfdef _getLineups(self):matches = self.driver.find_elements(By.CLASS_NAME, "kusmLq")nameInPanel = ""df = pd.DataFrame(columns=["{team}Player{i}".format(team="home" if i <=10 else "away", i=i+1 if i <=10 else i-10) for i in range(0,22)])df["homeTeam"] = []for match in matches:self.driver.execute_script("arguments[0].click()", match)#wait until panel is refreshedwaiter = WebDriverWait(driver=self.driver, timeout=10, poll_frequency=1)waiter.until(lambda drv: drv.find_element(By.CLASS_NAME, "dsMMht").text != nameInPanel)nameInPanel = self.driver.find_element(By.CLASS_NAME, "dsMMht").textif self._checkExistsByClass("jwanNG") and self.driver.find_element(By.CLASS_NAME, "jwanNG").text == "LINEUPS":lineupButton = self.driver.find_element(By.CLASS_NAME, "jwanNG")lineupButton.click()# wait until players are avilableWebDriverWait(self.driver, 20).until(EC.visibility_of_element_located((By.CLASS_NAME, "kDQXnl")))players = self.driver.find_elements(By.CLASS_NAME, "kDQXnl")playerNames=[]for player in players:playerNames.append(player.find_elements(By.CLASS_NAME, "sc-eDWCr")[2].accessible_name)playerNames = [self._isCaptain(playerName) for playerName in playerNames]playerNames.append(nameInPanel)df.loc[len(df)] = playerNameselse:df.loc[len(df), "homeTeam"] = nameInPanelreturn dfdef _isCaptain(self, name):if name.startswith("(c) "):name = name[4:]return name

数据框预览

总结上面的代码块,我们等到比赛的侧边菜单加载完毕,单击阵容按钮并获取球员姓名。我们需要注意一下,因为每个团队的队长的名字在网站上都是格式化的,所以我们创建了一个辅助函数来处理它。然后,我们将每场比赛的球员姓名存储在数据框中,最后在整个过程之后,我们将比赛信息与预测阵容连接起来。

结论

那么,今天就到此为止。在这篇文章中,我们构建了两个抓取工具,可以收集过去的足球比赛信息,也可以收集未来的比赛信息。这只是项目的开始,一旦您可以期待有关获取包含玩家信息的数据集、预测器建模和最后的投注策略模拟器的新文章。希望你喜欢它!

推荐书单

《Python从入门到精通(第2版)》

《Python从入门到精通(第2版)》从初学者角度出发,通过通俗易懂的语言、丰富多彩的实例,详细介绍了使用Python进行程序开发应该掌握的各方面技术。全书共分23章,包括初识Python、Python语言基础、运算符与表达式、流程控制语句、列表和元组、字典和集合、字符串、Python中使用正则表达式、函数、面向对象程序设计、模块、异常处理及程序调试、文件及目录操作、操作数据库、GUI界面编程、Pygame游戏编程、网络爬虫开发、使用进程和线程、网络编程、Web编程、Flask框架、e起去旅行网站、AI图像识别工具等内容。所有知识都结合具体实例进行介绍,涉及的程序代码都给出了详细的注释,读者可轻松领会Python程序开发的精髓,快速提升开发技能。除此之外,该书还附配了243集高清教学微视频及PPT电子教案。

《Python从入门到精通(第2版)》【摘要 书评 试读】- 京东图书京东JD.COM图书频道为您提供《Python从入门到精通(第2版)》在线选购,本书作者:明日科技,出版社:清华大学出版社。买图书,到京东。网购图书,享受最低优惠折扣!icon-default.png?t=N4P3https://item.jd.com/13284890.html

精彩回顾

ChatGPT教你如何用Python和Matplotlib绘图(上) 

ChatGPT教你如何用Python和Matplotlib绘图(下) 

《事半功倍,使用ChatGPT编写Python函数》

超快速,使用ChatGPT编写回归和分类算法

《如虎添翼,将ChatGPT和Python结合起来!》

《ChatGPT优化Python代码的小技巧》

《使用ChatGPT提升Python编程效率》 

微信搜索关注《Python学研大本营》

访问【IT今日热榜】,发现每日技术热点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/23521.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cas latex模板参考文献APA等引用格式(Elsevier期刊)

目录 一、在模板中引入需要的 .bst 文件&#xff0c;每个文件都是一种参考文献的格式 二、模板中引入.bst 文件的格式 三、在 \documentclass 之后&#xff0c;\begin{document} 之前&#xff0c;引入 natbib 包 四、在文章正文中引用参考文献 例如&#xff1a;期待的参考文献格…

作为测试人员,我们该如何看待AI

前几天看到一篇文章讨论从测试人员的角度去理解AI的&#xff0c;稍微翻译了一下。原文地址https://stevethedoc.wordpress.com/2023/06/18/how-should-we-view-ai-as-testers 上周三和周四&#xff0c;我有幸与我的两位同事Sushmitha Sivan和Bhavana Akula一起参加了伦敦的AI峰…

【Ai工具合集,一定有你需要的!】

花费了一天的时间测试了市面上各大Ai工具&#xff0c;然后帮大家整理总结出来了这些工具&#xff0c;一定记得点赞收藏保存&#xff0c;后面肯定会用到&#xff01; 使用说明 1.部分Ai工具需要魔法上网&#xff0c;请自行解决&#xff1b;部分工具需要收费&#xff0c;可以尝…

把 ChatGPT 加入 Flutter 开发,会有怎样的体验?

前言 ChatGPT 最近一直都处于技术圈的讨论焦点。它除了可作为普通用户的日常 AI 助手&#xff0c;还可以帮助开发者加速开发进度。声网社区的一位开发者"小猿"就基于 ChatGPT 做了一场实验。仅 40 分钟就实现了一个互动直播 Demo。他是怎么做的呢&#xff1f;他将整个…

加入Beezy GPT-4体验官俱乐部,成为高级AI功能“领航员”

目前&#xff0c;Beezy已率先接入GPT-4 API &#xff0c;无需科学上网&#xff0c;为您带来简单好用的智能体验。 GPT-4 VS GPT-3.5 一、优点 GPT-4和 GPT-3.5语言模型在前沿技术的推动下&#xff0c;都具备了相当出色的自然语言生成能力。相较于GPT-3.5&#xff0c; GPT-4 实现…

迎来新兴市场数字化转型红利,雅乐科技潇洒画出“向上曲线”

3月14日&#xff0c;“中东小腾讯”雅乐科技公布了最新一季财报。财报显示&#xff0c;雅乐科技2022年第四季度&#xff0c;营收7510万美元&#xff0c;同比增长11.2%&#xff1b;净利润为1660万美元&#xff0c;净利润率22.1%&#xff1b;2022年全年营收3.036亿美元&#xff0…

梦幻西游手游排队显示服务器已满,梦幻西游手游排队进不去 一直排队解决方法...

今天小编为大家带来了梦幻西游手游排队进不去 一直排队解决方法&#xff0c;感兴趣的朋友们可以跟着小编去下文了解一下哦&#xff01; 梦幻西游手游排队进不去&#xff0c;一直排队怎么办&#xff1f;游戏新开服&#xff0c;总是会有一堆服务器排队问题&#xff0c;那么梦幻西…

梦幻西游单机架设教程-端游篇

准备工具&#xff1a; GGE 服务端 客户端 服务器 源码 废话不多说教程开始 我们打开GEE双击打开ggemain.exe这个程序 程序打开之后点击右上角文件设置 关联lua文件和关联项目文件后保存 打开服务端找到服务端. sublime-projectl打开把127.0.0.1改成我们服务器的ip 5、把默认端口…

好玩的免费GM游戏整理汇总

前言 我所有架设的游戏发布和更新都会实时整理到本文 https://echeverra.cn/h5game &#xff0c;建议收藏。 游戏全部免费带GM后台&#xff08;可以免费充值发送游戏道具&#xff09;&#xff0c;且长期维护&#xff0c;其中大天使之剑和梦幻西游我会一直一直维护下去。 有人…

【手游服务端】梦幻西游十五门派端+教程+GM物品后台

下载链接&#xff1a;https://pan.baidu.com/s/1ds_xFq1Rd1_xC4515BRGXw 提取码&#xff1a;soho 【手游服务端】梦幻西游十五门派端教程GM物品后台

最新亲测转转交易猫闲鱼后台源码

教程&#xff1a;修改数据库账号密码直接使用。 下载程序&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

微信聊天记录导出工具WeChatExporter开源啦!

【2019年08月21日更新】 距离第一次发布软件已经有了许多新功能和稳定性上的提升&#xff0c;本文的一些内容已经过时&#xff0c;欢迎直接到GitHub上看ReadMe&#xff1a;https://github.com/tsycnh/WeChatExporter 之前曾经写过一个导出微信聊天记录的工具&#xff0c;偶尔自…

闲鱼跳转app源码+后台管理

教程&#xff1a;修改数据库账号密码直接使用。 源码带有教程! 下载程序&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

2021最新版闲鱼过模拟器

找了市面上的所有模拟器&#xff0c;有的不能登陆&#xff0c;有的黑屏&#xff0c;有的不能聊天等等&#xff0c;但功夫不负有心人&#xff0c;终于找到一款可以可以过闲鱼的模拟器&#xff0c;只需要简单的配置就可以&#xff0c;这个模拟器不改连打开都成问题&#xff0c;哈…

转转交易猫闲鱼后台源码 功能强大免授权

不用设置什么伪静态&#xff0c;也不用安装什么扩展&#xff0c;正常搭建即可。 搭建教程:添加网站→上传源码→解压源码→导入数据库→修改数据库路径config/Conn.php 下载源码&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

闲鱼转转源码+后台你懂的App

介绍&#xff1a; 数据库修改地址/config/Conn.php 和闲鱼转转相似度百分之90 什么源码你们懂的 导入数据库文件后台帐号admin可自行发布商品&#xff0c;设置商品出售价格。独立后台 第三方支付接口可对商品进行 点赞和留言以及自定义浏览数在线购买商品&#xff0c;可实…

仿交易猫 转转闲鱼源码 多版本合一

教程&#xff1a;修改数据库账号密码直接使用。 下载程序&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

网络聊天室(群发助手)—— C++

网络聊天室&#xff08;群发助手 文章目录 网络聊天室&#xff08;群发助手 &#xff08;一&#xff09;项目要求&#xff08;二&#xff09;开发环境&#xff08;二&#xff09;系统模块设计&#xff08;三&#xff09;视频演示&#xff08;四&#xff09;源代码 &#xff08;…

上班聊天,摸鱼神器,手写一款即时通讯工具(附源码!!!)

文章目录 即时通讯工具客户端服务端1、链接2、登录3、其他方法3.1、读取客户端的消息3.2、给客户端发送消息3.3、日志记录3.4、工具集合3.5、ChatSocket 服务端部署优点与缺点最后 认真工作不叫做赚钱&#xff0c;那叫做用劳动换取报酬&#xff0c;上班摸鱼才是真的赚钱。 即时…

闲鱼软件监控搜索采集hook请求签名算法-X-Sign和强制聊天

抓包方法和X-Sign算法 详情页所有数据都有 这些内容是的整个详情页的字段 以及聊天抓包分析 直接用易语言写成了 成品 可以直接读取数据