Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hopeful Contribution #107

Open
wants to merge 2 commits into
base: v4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions basketball_reference_web_scraper/client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import requests

from basketball_reference_web_scraper import http_client
from basketball_reference_web_scraper.errors import InvalidSeason, InvalidDate
from basketball_reference_web_scraper.errors import InvalidSeason, InvalidDate, InvalidPlayer
from basketball_reference_web_scraper.output import output
from basketball_reference_web_scraper.writers import CSVWriter, RowFormatter, \
BOX_SCORE_COLUMN_NAMES, SCHEDULE_COLUMN_NAMES, PLAYER_SEASON_TOTALS_COLUMN_NAMES, \
Expand Down Expand Up @@ -30,12 +30,104 @@ def player_box_scores(day, month, year, output_type=None, output_file_path=None,
)


def single_player_box_scores(player_name, day, month, year, output_type=None, output_file_path=None, output_write_option=None,
json_options=None):
try:
values = http_client.player_box_scores(day=day, month=month, year=year)
except requests.exceptions.HTTPError as http_error:
if http_error.response.status_code == requests.codes.not_found:
raise InvalidDate(day=day, month=month, year=year)
else:
raise http_error

for player in values:
if player['name'] == player_name:
return output(
values=player,
output_type=output_type,
output_file_path=output_file_path,
output_write_option=output_write_option,
csv_writer=CSVWriter(
column_names=BOX_SCORE_COLUMN_NAMES,
row_formatter=RowFormatter(data_field_names=BOX_SCORE_COLUMN_NAMES)
),
json_options=json_options,
)


def single_player_season_totals(player_name, season_end_year, output_type=None, output_file_path=None,
output_write_option=None, json_options=None):
values = players_season_totals(season_end_year=season_end_year)

for player in values:
if player['name'] == player_name:
jersey_number = http_client.player_number(player['name'])
player['jersey_number'] = jersey_number
return output(
values=player,
output_type=output_type,
output_file_path=output_file_path,
output_write_option=output_write_option,
csv_writer=CSVWriter(
column_names=PLAYER_SEASON_TOTALS_COLUMN_NAMES,
row_formatter=RowFormatter(data_field_names=PLAYER_SEASON_TOTALS_COLUMN_NAMES)
),
json_options=json_options,
)


def single_player_advanced_season_totals(player_name, season_end_year, output_type=None, output_file_path=None,
output_write_option=None, json_options=None):
values = players_advanced_season_totals(season_end_year=season_end_year)

for player in values:
if player_name in values:
jersey_number = http_client.player_number(player['name'])
player['jersey_number'] = jersey_number
return output(
values=player,
output_type=output_type,
output_file_path=output_file_path,
output_write_option=output_write_option,
csv_writer=CSVWriter(
column_names=PLAYER_ADVANCED_SEASON_TOTALS_COLUMN_NAMES,
row_formatter=RowFormatter(data_field_names=PLAYER_ADVANCED_SEASON_TOTALS_COLUMN_NAMES)
),
json_options=json_options,
)


def get_jersey_number(player_name, output_type=None, output_file_path=None, output_write_option=None,
json_options=None):
try:
values = http_client.player_number(player_name)
except requests.exceptions.HTTPError as http_error:
if http_error.response.status_code == requests.codes.not_found:
raise InvalidPlayer(player_name=player_name)
else:
raise http_error
return output(
values=values,
output_type=output_type,
output_file_path=output_file_path,
output_write_option=output_write_option,
csv_writer=CSVWriter(
column_names=PLAYER_SEASON_TOTALS_COLUMN_NAMES,
row_formatter=RowFormatter(data_field_names=PLAYER_SEASON_TOTALS_COLUMN_NAMES)
),
json_options=json_options,
)


def did_player_start(player_name, day, month, year):
# Still have to implement
return True

def season_schedule(season_end_year, output_type=None, output_file_path=None, output_write_option=None,
json_options=None):
try:
values = http_client.season_schedule(season_end_year)
except requests.exceptions.HTTPError as http_error:
# https://github.com/requests/requests/blob/master/requests/status_codes.py#L58
if http_error.response.status_code == requests.codes.not_found:
raise InvalidSeason(season_end_year=season_end_year)
else:
Expand Down
16 changes: 11 additions & 5 deletions basketball_reference_web_scraper/errors.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
class InvalidDate(Exception):
def __init__(self, day, month, year):
message = "Date with year set to {year}, month set to {month}, and day set to {day} is invalid"\
message = "Date with year set to {year}, month set to {month}, and day set to {day} is invalid" \
.format(
year=year,
month=month,
day=day,
)
year=year,
month=month,
day=day,
)
super().__init__(message)


class InvalidSeason(Exception):
def __init__(self, season_end_year):
message = "Season end year of {season_end_year} is invalid".format(season_end_year=season_end_year)
super().__init__(message)


class InvalidPlayer(Exception):
def __init__(self, player_name):
message = f'Player name of {player_name} in invalid'
super().__init__(message)
129 changes: 129 additions & 0 deletions basketball_reference_web_scraper/four_factors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
from basketball_reference_web_scraper import client
from datetime import datetime
import functools


def get_team_score(team, num_games, sched, last_index, box_score_dict):
num_games = int(num_games)
recent_games = []
recent_opp_games = []

while len(recent_games) < num_games:
game = sched[last_index]
opponent = None
if game['home_team'] == team:
opponent = game['away_team']
elif game['away_team'] == team:
opponent = game['home_team']

if opponent is not None:
day = game['start_time'].day
month = game['start_time'].month
year = game['start_time'].year
key = game['start_time'].date()

if key in box_score_dict:
box_scores = box_score_dict[key]
else:
box_scores = client.team_box_scores(day=day, month=month, year=year)
box_score_dict[key] = box_scores

for i in range(0, len(box_scores)):
if box_scores[i]['team'] == team:
recent_games.append(box_scores[i])
elif box_scores[i]['team'] == opponent:
recent_opp_games.append(box_scores[i])

last_index -= 1
if last_index < 0:
break

ft_att = 0
ft_made = 0
fg_att = 0
fg_made = 0
off_reb = 0
def_reb = 0
to = 0
num_poss = 0

opp_ft_att = 0
opp_ft_made = 0
opp_fg_att = 0
opp_fg_made = 0
opp_def_reb = 0
opp_off_reb = 0
opp_to = 0
opp_num_poss = 0

for i in recent_games:
ft_att += i['attempted_free_throws']
ft_made += i['made_free_throws']
fg_att += i['attempted_field_goals']
fg_made += i['made_field_goals'] + .5 * i['made_three_point_field_goals']
off_reb += i['offensive_rebounds']
def_reb += i['defensive_rebounds']
to += i['turnovers']
num_poss += i['attempted_field_goals'] + i['turnovers'] + i['attempted_free_throws'] / 1.8

for i in recent_opp_games:
opp_ft_att += i['attempted_free_throws']
opp_ft_made += i['made_free_throws']
opp_fg_att += i['attempted_field_goals']
opp_fg_made += i['made_field_goals'] + .5 * i['made_three_point_field_goals']
opp_off_reb += i['offensive_rebounds']
opp_def_reb += i['defensive_rebounds']
opp_to += i['turnovers']
opp_num_poss += i['attempted_field_goals'] + i['turnovers'] + i['attempted_free_throws'] / 1.8

efg = fg_made / fg_att
ft = ft_made / fg_att
orp = off_reb / (off_reb + opp_def_reb)
drp = def_reb / (opp_off_reb + def_reb)
turnover = to / num_poss

if opp_fg_att != 0:
opp_efg = opp_fg_made / opp_fg_att
opp_ft = opp_ft_made / opp_fg_att
else:
opp_efg = 0
opp_ft = 0

# opp_orp = opp_off_reb / (opp_off_reb + def_reb)
# opp_drp = opp_def_reb / (off_reb + opp_def_reb)
if opp_num_poss != 0:
opp_turnover = opp_to / opp_num_poss
else:
opp_turnover = 0

off_score = .43 * efg - .39 * turnover + .1 * orp + .08 * ft
def_score = -.43 * opp_efg + .39 * opp_turnover + .1 * drp - .08 * opp_ft

return off_score + def_score


def compare(a, b):
if a[1] > b[1]:
return -1
else:
return 1


def run_four_factors(num_games):
today = datetime.today()
sched = client.season_schedule(season_end_year=2020)
box_score_dict = {}
final_scores = []

for i in range(len(sched) - 1, 0, -1):
game = sched[i]
if today.date() == game['start_time'].date():
home_score = get_team_score(game['home_team'], num_games, sched, i, box_score_dict)
final_scores.append((game['home_team'], home_score))
# print(game['home_team'], home_score, '\n')

away_score = get_team_score(game['away_team'], num_games, sched, i, box_score_dict)
final_scores.append((game['away_team'], away_score))

sorted_scores = sorted(final_scores, key=functools.cmp_to_key(compare))
return sorted_scores
Loading