def test_get_matchups(): mf = Misc_Functions() matches = { "Philadelphia Flyers at Buffalo Sabres": ["B.Brian Elliott", "L.Linus Ullmark"], "New York Islanders at Pittsburgh Penguins": ["S.Semyon Varlamov", "T.Tristan Jarry"], "Edmonton Oilers at Toronto Maple Leafs": ["M.Mike Smith", "M.Michael Hutchinson"], "Anaheim Ducks at Colorado Avalanche": ["R.Ryan Miller", "P.Philipp Grubauer"], "Winnipeg Jets at Calgary Flames": ["C.Connor Hellebuyck", "J.Jacob Markstrom"], "Los Angeles Kings at Vegas Golden Knights": ["J.Jonathan Quick", "R.Robin Lehner"], "Minnesota Wild at San Jose Sharks": ["C.Cam Talbot", "M.Martin Jones"] } test_matchups = mf.get_matchups(matches) result = [["Philadelphia Flyers", "Buffalo Sabres"], ["New York Islanders", "Pittsburgh Penguins"], ["Edmonton Oilers", "Toronto Maple Leafs"], ["Anaheim Ducks", "Colorado Avalanche"], ["Winnipeg Jets", "Calgary Flames"], ["Los Angeles Kings", "Vegas Golden Knights"], ["Minnesota Wild", "San Jose Sharks"]] if test_matchups == result: print("Matchups: PASS") else: print("Matchups: FAIL") print(f'Returned: {test_matchups}') print( "Expected: [['Philadelphia Flyers', 'Buffalo Sabres'], ['New York Islanders', 'Pittsburgh Penguins'], ['Edmonton Oilers', 'Toronto Maple Leafs'], [ \ 'Anaheim Ducks', 'Colorado Avalanche'], ['Winnipeg Jets', 'Calgary Flames'], ['Los Angeles Kings', 'Vegas Golden Knights'], ['Minnesota Wild', 'San Jose Sharks']]" )
def get_scores(self): mf = Misc_Functions() html = open('results_test.html', "r") # html = mf.get_page_source( # f'http://www.nhl.com/ice/m_scores.htm', 1) soup = BeautifulSoup(html, 'html.parser') scores = [] matches = soup.find_all('table', class_='gmDisplay finalState') for match in matches: contents = match.find_all('tr') n = 0 for content in contents: if n == 0: pass else: content = content.get_text().split('\n').remove('') content[1] = content[1][0] scores.append(content) n += 1 n = 0 temp_result, result = [], [] for score in scores: temp_result.append(score) if n == 1: result.append(temp_result) temp_result = [] n = -1 n += 1 print(result) for n in result: print(n)
def get_injuries(self): mf = Misc_Functions() url = "https://www.espn.com/nhl/injuries" soup = BeautifulSoup(mf.get_page_source(url, 1), 'html.parser') card = soup.find('div', class_="page-container cf") teams = card.find_all('span', class_="injuries__teamName ml2") players = card.find_all('tbody', class_="Table__TBODY") injured = [] for player in players: stats = player.find_all('tr') for tr in stats: name = tr.find('a').get_text().split(' ') try: name = f'{name[0][0]}.{name[0]} {name[1]}' except IndexError: continue injured.append(name) return injured
class Predict_GA(): def __init__(self, goalies, offenses): self.goalie = Goalie_Functions() self.misc = Misc_Functions() self.goalies = goalies self.offenses = offenses def _get_opposing_score(self, goalie): team = self.misc.get_player_team(goalie) for offense in self.offenses: if team != offense[0]: return float(offense[1]) def get_prediction(self, array_x, array_y, offense_score): x = np.array(array_x).reshape((-1, 1)) y = np.array(array_y) model = LinearRegression() model.fit(x, y) if model.coef_ < 0: return -1 return float(model.coef_ * offense_score + model.intercept_) def get_ga(self): predictions = [] for goalie in self.goalies: performances = self.goalie.get_goalie_past_performance( [goalie], (len(os.listdir('./matchups')) - 1)) array_x, array_y = [], [] for performance in performances: if performance[3] != 'N/A': array_x.append(performance[4]) array_y.append(performance[3]) if len(array_x) > 1: opposing_score = self._get_opposing_score(goalie) prediction = self.get_prediction(array_x, array_y, opposing_score) else: continue if prediction > 0: predictions.append([goalie, prediction]) return predictions
class Starting_Goalies: def __init__(self): self.mf = Misc_Functions() def get_starting_goalies(self): html = self.mf.get_page_source( 'https://www.dailyfaceoff.com/starting-goalies/', 3) soup = BeautifulSoup(html, 'html.parser') card = soup.find('div', class_='starting-goalies-list stat-cards-list') names = card.find_all('h4') temp_matchups = [] n = 0 # strength = card.find_all('h5', class_='news-strength not-confirmed') # for news in strength: # print(news.get_text()) for __ in range(len(names) // 3): temp = [] for __ in range(3): if names[n].get_text() == 'Cal Petersen': temp.append('Calvin Petersen') else: temp.append(names[n].get_text()) n += 1 temp_matchups.append(temp) matchups = {} for matchup in temp_matchups: matchups[matchup[0]] = {} matchups[matchup[0]] = [ f'{matchup[1][0]}.{matchup[1]}', f'{matchup[2][0]}.{matchup[2]}' ] return matchups
def __init__(self): self.mf = Misc_Functions()
class Goalie_Functions(): def __init__(self): self.mf = Misc_Functions() def get_goalie_score(self, matchup: list[str]) -> list[str]: result = [] for goalie in matchup: score = 0 try: svp = float(self.mf.recent_data['goalies'][goalie]['sv%']) so = float(self.mf.recent_data['goalies'][goalie]['so']) l = int(self.mf.recent_data['goalies'][goalie]['l']) gs = int(self.mf.recent_data['goalies'][goalie]['gs']) ga = int(self.mf.recent_data['goalies'][goalie]['ga']) sa = int(self.mf.recent_data['goalies'][goalie]['sa']) if ga == 0: score = ((gs) + (svp) + sa) * (1 + so * .25) elif l == 0: score = ((gs) + (svp) + (sa / ga)) * (1 + so * .25) else: score = ((gs / l) + (svp) + (sa / ga)) * (1 + so * .25) except KeyError: print(f'No data for {goalie}') continue team = self.mf.get_player_team(goalie) result.append([goalie, team, "{:.2f}".format(score)]) return result def _get_goalie_last_matchup(self, data, i, team, n): offense = Skater_Functions() matchup = f'./matchups/matchups_{self.mf.get_date(n - i)}.json' opposing_team = str with open(matchup) as f: matchup_data = json.load(f) for element in matchup_data: if team in element: for teams in element: if element == team: pass opposing_team = team continue result = [] try: for skater in data['teams'][opposing_team]: try: result.append( offense.get_skater_score( data['teams'][opposing_team][skater])) except: continue return sum(result) / len(result) except KeyError: return 0 def get_goalie_past_performance(self, matchup: list[str], n: int = 7) -> list[str]: result = [] for goalie in matchup: last_gp, last_ga, gaa = 0, 0, 0 team = self.mf.get_player_team(goalie) for i in range(n): current_file = f'./nhl_stats/{self.mf.get_date(n - i)}.json' with open(current_file) as f: data = json.load(f) try: gp = data['goalies'][goalie]['gp'] ga = data['goalies'][goalie]['ga'] gaa = data['goalies'][goalie]['gaa'] except KeyError: continue if last_gp == 0: last_gp, last_ga = gp, ga continue if gp == last_gp: result.append( [goalie, gaa, self.mf.get_date(n - i), 'N/A', 'N/A']) else: self._get_goalie_last_matchup(data, i, team, n) result.append([ goalie, gaa, self.mf.get_date(n - i), int(ga) - int(last_ga), self._get_goalie_last_matchup(data, i, team, n) ]) last_ga, last_gp = ga, gp return result
def __init__(self, goalies, offenses): self.goalie = Goalie_Functions() self.misc = Misc_Functions() self.goalies = goalies self.offenses = offenses
async def main(): mf = Misc_Functions() matchups = f'./matchups/matchups_{mf.get_date(0)}.json' today_data = f'./nhl_stats/{mf.get_date(0)}.json' yesterday_data = f'./nhl_stats/{mf.get_date(1)}.json' starting_goalies = mf.read_data('starting_goalies') def get_report(): skaters = Skater_Functions() goalies = Goalie_Functions() matchup = [] print( f'\n{bcolors.HEADER}{bcolors.BOLD}{datetime.datetime.now()}{bcolors.ENDC}\n \n') for matchups in starting_goalies: matchup = matchups.split(' at ') matchup[0], matchup[1] = matchup[0].strip(), matchup[1].strip() print(f'{bcolors.BOLD}{matchups}{bcolors.ENDC}') print('\nGoalie Performance') for gme_ds in goalies.get_goalie_past_performance(starting_goalies[matchups]): if gme_ds[3] == 'N/A': print( f'{gme_ds[0]} ({gme_ds[1]}) {gme_ds[2]}: {bcolors.WARNING}No Game{bcolors.ENDC}') else: print( f'{gme_ds[0]} ({gme_ds[1]}) {gme_ds[2]}: {gme_ds[3]} ga to a {"{:.4f}".format(gme_ds[4])} offense') print() for goalie in goalies.get_goalie_score(starting_goalies[matchups]): print(f'{goalie[0]} ({goalie[1]}): {goalie[2]}') print('\nOffensive Matchup') for offense in skaters.get_offense_score(matchup): print(offense[0], offense[1]) print('\nEstimated Goals Against') pg = Predict_GA( starting_goalies[matchups], skaters.get_offense_score(matchup)) print(pg.get_ga()) print() if path.exists(yesterday_data) == False and datetime.datetime.now().hour < 16: players = Player_Stats() print( f'{bcolors.FAIL}Forgot to run yesterday\'s data. Be sure to change the file date and run again{bcolors.ENDC}') print('\n \n \n') players.write_daily_data() sys.exit(0) # Adjust hour based on when you want the goalie matchups # 15 should be standard time for weekdays if datetime.datetime.now().hour <= 8: mf = Misc_Functions() starters = Starting_Goalies() ir = Injury_Report() print('Refreshing Starting Goalies... \n') starting_goalies = starters.get_starting_goalies() print('Refreshing Injuries... \n') injuries = ir.get_injuries() mf.write_data(starting_goalies, "starting_goalies") mf.write_data(injuries, "injuries") if path.exists(matchups) == False: matchups = mf.get_matchups(starting_goalies) mf.write_data(matchups, "matchups") if path.exists(today_data) == False and datetime.datetime.now().hour > 20: players = Player_Stats() print() print(f'{bcolors.OKGREEN}Adding tonight\'s data{bcolors.ENDC}') print() time.sleep(2) players.write_daily_data() # also write scores data get_report()
class Player_Stats(): def __init__(self): self.mf = Misc_Functions() def html_to_text(self, html_text): result = [] temp_res = [] for line in html_text: line = line.get_text().split('\n') for element in line: if element: temp_res.append(element) temp_res[0] = temp_res[0].lstrip() result.append(temp_res) temp_res = [] return result def format_player(self, player, ptype): player_dict = {} if ptype == 'goalie': player_dict['player'] = player[0] player_dict['gp'] = player[1] player_dict['gs'] = player[2] player_dict['w'] = player[3] player_dict['l'] = player[4] player_dict['t'] = player[5] player_dict['ot'] = player[6] player_dict['sa'] = player[7] player_dict['ga'] = player[8] player_dict['gaa'] = player[9] player_dict['s'] = player[10] player_dict['sv%'] = player[11] player_dict['so'] = player[12] player_dict['min'] = player[13] elif ptype == 'skater': player_dict['player'] = player[0] player_dict['gp'] = player[1] player_dict['g'] = player[2] player_dict['a'] = player[3] player_dict['p'] = player[4] player_dict['+/-'] = player[5] player_dict['pim'] = player[6] player_dict['ppg'] = player[7] player_dict['ppp'] = player[8] # smg is a typo for shg player_dict['smg'] = player[9] player_dict['shp'] = player[10] player_dict['gwg'] = player[11] player_dict['otg'] = player[12] player_dict['s'] = player[13] player_dict['s%'] = player[14] player_dict['fo%'] = player[15] return player_dict def get_data(self, team_names): nhl_stats = {} nhl_stats['goalies'] = {} nhl_stats['skaters'] = {} nhl_stats['teams'] = {} for team in team_names: url = f'https://www.nhl.com/{team}/stats/regular-season' html = self.mf.get_page_source(url, 2) soup = BeautifulSoup(html, 'html.parser') team_title = soup.find('title') try: team_name = team_title.get_text().split('|')[2].strip() print(f"{team_name}, complete") except IndexError as i: print(f"{team}: {i}") continue nhl_stats['teams'][team_name] = {} # Goalies goalie_div = soup.find('div', id='goalie-table') goalies = goalie_div.find_next('tbody').find_all('tr') # Skaters skater_div = soup.find('div', id='skater-table') skaters = skater_div.find_next('tbody').find_all('tr') skaters = self.html_to_text(skaters) goalies = self.html_to_text(goalies) for goalie in goalies: goalie_dict = self.format_player(goalie, 'goalie') nhl_stats['goalies'][goalie[0]] = goalie_dict team_goalie_dict = self.format_player(goalie, 'goalie') nhl_stats['teams'][team_name][goalie[0]] = team_goalie_dict for skater in skaters: skater_dict = self.format_player(skater, 'skater') nhl_stats['skaters'][skater[0]] = skater_dict team_skater_dict = self.format_player(skater, 'skater') nhl_stats['teams'][team_name][skater[0]] = team_skater_dict return nhl_stats def write_daily_data(self): all_teams = ['ducks', 'coyotes', 'canucks', 'bruins', 'predators', 'blues', 'flames', 'sabres', 'hurricanes', 'blackhawks', 'avalanche', 'stars', 'redwings', 'oilers', 'panthers', 'kings', 'wild', 'canadiens', 'devils', 'islanders', 'rangers', 'senators', 'flyers', 'penguins', 'sharks', 'bluejackets', 'lightning', 'mapleleafs', 'goldenknights', 'capitals', 'jets'] stats = self.get_data(all_teams) self.mf.write_data(stats, "perm")