Browse Source

Update to version 2.0 script + requirements

bryan 3 years ago
parent
commit
bd2ecb5bcb
2 changed files with 186 additions and 195 deletions
  1. 178 195
      nba_playoffs_game_updater.py
  2. 8 0
      requirements.txt

+ 178 - 195
nba_playoffs_game_updater.py

@@ -2,218 +2,201 @@
 
 import gspread
 from oauth2client.service_account import ServiceAccountCredentials
-
-import sys
-import nba_py.player as player
-
 import datetime
 import time
-
 import timeout_decorator
+from nba_api.stats.static import players
+from nba_api.stats.endpoints import playergamelog
 
-_spreadsheetKey = "12Zv95ZMJ008KXC5ytVnBusjX9wUnpOg0TOLwmxMNOTQ"
+#spreadsheet_key = '12Zv95ZMJ008KXC5ytVnBusjX9wUnpOg0TOLwmxMNOTQ' # 2018 Official
+spreadsheet_key = '14pHOScaGXvN83iCca6_5p6QoViYvo223cIJD9nnl7TI' # 2019 Test
+json_keyfile = 'NBA Playoffs Game-1f9a46f0715c.json'
+#current_day = "" # today, else:
+current_day = datetime.date(2018, 4, 14) # set date manually
+nba_cooldown = 1 # in seconds, don't hammer the NBA.com API too hard
 
+####################################################################################
 
-def _getSheets(_key):
+def getWorksheet(spreadsheet_key, json_keyfile):
   scope = ['https://spreadsheets.google.com/feeds',
            'https://www.googleapis.com/auth/drive']
-
-  _credentials = ServiceAccountCredentials.from_json_keyfile_name('NBA Playoffs Game-1f9a46f0715c.json', scope)
-
-  _gc = gspread.authorize(_credentials)
-
-  # open spreadsheet
-  _spreadsheet = _gc.open_by_key(_key)
-  
-  # open worksheet
-  _statsSheet = _spreadsheet.get_worksheet(0)
-  _leaderSheet = _spreadsheet.get_worksheet(1)
-  
-  # count participants
-  _numParticipants = _leaderSheet.row_count - 1
-
-  return _statsSheet, _leaderSheet
-  
-  
-def _getNumParticipants(_leaderSheet):
-
-  _numParticipants = _leaderSheet.row_count - 1
-  
-  return _numParticipants
-  
-
-def _getRowsFromDate(_statsSheet, _numParticipants):
-
-  # get today
-  _today = datetime.date.today()
-  # else manually set the date
-  #_today = datetime.date(2018, 5, 16)
-  
-  _urlDate = _today.strftime('%m/%d/%Y')
-
-  # count rows
-  _shtRows =  _statsSheet.row_count
-  
-  # set first date cell
-  _startRow = 4
-  
-  # get date cells
-  while _startRow <= _shtRows:
-    _dateCell = _statsSheet.cell(_startRow, 1, value_render_option='UNFORMATTED_VALUE')
-    _daysSince1900 = _dateCell.value    
-    _date = datetime.date(1899, 12, 30) + datetime.timedelta(int(_daysSince1900))
-
-    if _today == _date:
-      break
-    elif _today > _date:
-      _startRow += _numParticipants
-    else:
-      _startRow = 0 # no games today
-      break
-      
-  _lastRow = _startRow + _numParticipants - 1
-  
-  return _startRow, _lastRow, _urlDate
-
-
-def _getPlayersCells(_statsSheet, _startRow, _lastRow):
-   
-  _playersCells = _statsSheet.range(_startRow, 3, _lastRow, 3)
-  
-  # filter cells
-  for _playerCell in _playersCells[:]:
-
-    if _playerCell.value == "":
-      _playersCells.remove(_playerCell)
-  
-  return _playersCells
-  
-
-def _getPlayerFirstNameLastName(_player):
-  _firstNamelastName = _player.split()
-  _firstName = _firstNamelastName[0]
-  _firstName = _firstName.replace('.', '')
-  _lastName = _firstNamelastName[1]
-  
-  return _firstName, _lastName
-  
-
-@timeout_decorator.timeout(10)  
-def _getPlayerID(_firstName, _lastName):
-  _playerID = player.get_player(first_name=_firstName,last_name=_lastName)
-  return _playerID
-
+  credentials = ServiceAccountCredentials.from_json_keyfile_name(json_keyfile, scope)
+  gc = gspread.authorize(credentials)
+  spreadsheet = gc.open_by_key(spreadsheet_key)
+  worksheet = spreadsheet.get_worksheet(0)
+  return worksheet
+
+def setDates(current_day):
+  if current_day == "":
+    current_day = datetime.datetime.now() - datetime.timedelta(hours=3) # in case games go past midnight
+    current_day = current_day.date()
+  url_date = current_day.strftime('%m/%d/%Y')
+  current_year = current_day.year
+  if current_day.month > 6:
+    current_season = str(current_year) + "-" + str(current_year + 1)[2:]
+  else:
+    current_season = str(current_year - 1) + "-" + str(current_year)[2:]
+  return url_date, current_season, current_day
+  
+def getFirstRowLastRow(worksheet, current_day):
+  date_col_values = worksheet.col_values(1) # get all date cell values from column 1
+  final_row = len(date_col_values) # get number of rows in spreadsheet
+  date_cells = worksheet.range('A4:A'+str(final_row)) # get all date cells
+  first_row = ""
+  last_row = ""
+  for date_cell in date_cells:
+    if first_row != "":
+      if date_cell.row == final_row:
+        last_row = final_row
+      elif date_cell.value != "":
+        last_row = date_cell.row - 1
+        break
+      else:
+        continue
+    elif date_cell.value != "":
+      date_cell_day = datetime.datetime.strptime(date_cell.value + " " + str(current_day.year), '%A, %B %d %Y')
+      date_cell_day = date_cell_day.date()
+      if date_cell_day == current_day:
+        first_row = date_cell.row
+  return first_row, last_row
+
+def parsePlayersCells(todays_cells):
+  player_cells = []
+  player_names = []
+  for cell in todays_cells:
+    if cell.col == 3 and cell.value != "":
+      player_cells.append(cell)
+      player_name = cleanPlayerName(cell)
+      player_names.append(player_name)
+  player_names_unique = list(dict.fromkeys(player_names))
+  return player_cells, player_names_unique
+    
+def cleanPlayerName(player_cell):
+  raw_name = player_cell.value
+  first_name_last_name = raw_name.split()
+  first_name = first_name_last_name[0]
+  first_name = first_name.replace('.', '')
+  last_name = first_name_last_name[1]
+  player_name = first_name + ' ' + last_name
+  return player_name
+  
+def badName(worksheet, player_cell):
+  worksheet.update_cell(player_cell.row, 12, "Fix name, then delete this message!")
 
 @timeout_decorator.timeout(10)
-def _getPlayerStats(_playerID, _urlDate):
-
-  _playerStats = {}
-  _playerGameLogs = player.PlayerGameLogs(player_id=_playerID,
-                                          season_type='Playoffs',
-                                          date_from=_urlDate,
-                                          date_to=_urlDate)
-
-  for _playerGameLog in _playerGameLogs.info():
-    for _stat in _playerGameLog.keys():
-      _playerStats[_stat] = _playerGameLog[_stat]
-
-  return _playerStats
-
-
-def _updatePlayerStatsCells(_statsSheet, _playerCell, _playerStats):
-
-  _rowNumber = _playerCell.row
-
-  for _stat in _playerStats:
-    if _stat == "PTS" and _playerStats[_stat] != "":
-      _statsSheet.update_cell(_rowNumber, 4, _playerStats[_stat])
-    elif _stat == "REB" and _playerStats[_stat] != "":
-      _statsSheet.update_cell(_rowNumber, 5, _playerStats[_stat])
-    elif _stat == "AST" and _playerStats[_stat] != "":
-      _statsSheet.update_cell(_rowNumber, 6, _playerStats[_stat])
-    elif _stat == "STL" and _playerStats[_stat] != "":
-      _statsSheet.update_cell(_rowNumber, 7, _playerStats[_stat])
-    elif _stat == "BLK" and _playerStats[_stat] != "":
-      _statsSheet.update_cell(_rowNumber, 8, _playerStats[_stat])
-    elif _stat == "TOV" and _playerStats[_stat] != "":
-      _statsSheet.update_cell(_rowNumber, 9, _playerStats[_stat])
-
-    if _stat == "WL" and _playerStats[_stat] != "":
-      _statsSheet.update_cell(_rowNumber, 11, _playerStats[_stat])
+def getPlayerStats(player_id, url_date, current_season):
+  player_stats = {}
+  player_game_logs = playergamelog.PlayerGameLog(player_id=player_id,
+                                          season_all=current_season,
+                                          league_id_nullable='00',
+                                          season_type_all_star='Playoffs',
+                                          date_from_nullable=url_date,
+                                          date_to_nullable=url_date)
+  player_game_logs = player_game_logs.get_dict()
+  player_game_logs_results = player_game_logs.get('resultSets')[0]
+  player_game_logs_headers = player_game_logs_results.get('headers')
+  player_game_logs_values = player_game_logs_results.get('rowSet')[0]
+  player_stats_dict = dict(zip(player_game_logs_headers, player_game_logs_values))
+  return player_stats_dict
+
+@timeout_decorator.timeout(60)
+def buildStatsDict(player_names_unique, url_date, current_season):
+  stats_dict = {}
+  for player_name in player_names_unique:
+    print("Getting " + player_name + "\'s stats from NBA.com")
+    player_info = players.find_players_by_full_name(player_name)
+    player_id = player_info[0].get('id')
+    player_stats_dict = getPlayerStats(player_id, url_date, current_season)
+    stats_dict[player_name] = player_stats_dict
+    time.sleep(nba_cooldown)
+  return stats_dict
+
+def checkStatsDict(player_name, stats_dict):
+  player_stats_dict = stats_dict.get(player_name)
+  return player_stats_dict
+
+def updatePlayerStatsLocal(todays_cells, player_cell, player_stats_dict, update):
+  for cell in todays_cells:
+    if cell.row == player_cell.row:
+      if cell.col == 4 and player_stats_dict.get("PTS") != "" and str(cell.value) != str(player_stats_dict.get("PTS")):
+        cell.value = int(player_stats_dict.get("PTS"))
+        update = True
+      elif cell.col == 5 and player_stats_dict.get("REB") != "" and str(cell.value) != str(player_stats_dict.get("REB")):
+        cell.value = int(player_stats_dict.get("REB"))
+        update = True
+      elif cell.col == 6 and player_stats_dict.get("AST") != "" and str(cell.value) != str(player_stats_dict.get("AST")):
+         cell.value = int(player_stats_dict.get("AST"))
+         update = True
+      elif cell.col == 7 and player_stats_dict.get("STL") != "" and str(cell.value) != str(player_stats_dict.get("STL")):
+         cell.value = int(player_stats_dict.get("STL"))
+         update = True
+      elif cell.col == 8 and player_stats_dict.get("BLK") != "" and str(cell.value) != str(player_stats_dict.get("BLK")):
+         cell.value = int(player_stats_dict.get("BLK"))
+         update = True
+      elif cell.col == 9 and player_stats_dict.get("TOV") != "" and str(cell.value) != str(player_stats_dict.get("TOV")):
+         cell.value = int(player_stats_dict.get("TOV"))
+         update = True
+      elif cell.col == 10 and player_stats_dict.get("WL") != "" and str(cell.value) != str(player_stats_dict.get("WL")):
+         cell.value = str(player_stats_dict.get("WL"))
+         update = True
+  return todays_cells, update
+      
 
 
-def _badName(_statsSheet, _playerCell):
-  _rowNumber = _playerCell.row
-  _statsSheet.update_cell(_rowNumber, 12, "Fix name, then delete this message!")
+if __name__ == "__main__":
 
-###### EXECUTE ########
+  while True:
 
-while True:
+    url_date, current_season, current_day = setDates(current_day)
+    
+    try:
+      worksheet = getWorksheet(spreadsheet_key, json_keyfile)
+      first_row, last_row = getFirstRowLastRow(worksheet, current_day)
+      if first_row == "":
+        print("No games today! Pausing for 1000 seconds...")
+        time.sleep(1000)
+        continue
+      todays_cells = worksheet.range(first_row, 3, last_row, 10)
+      print("Getting a list of today's players...")
+      player_cells, player_names_unique = parsePlayersCells(todays_cells)
+      print(player_names_unique)
+    except gspread.exceptions.APIError:
+      print("API overloaded, retrying in 10 seconds...")
+      time.sleep(10)
+      continue
+    except:
+      time.sleep(10)
+      continue
 
-  try:
-    _statsSheet, _leaderSheet = _getSheets(_spreadsheetKey)
-    _numParticipants = _getNumParticipants(_leaderSheet)
-    _startRow, _lastRow, _urlDate = _getRowsFromDate(_statsSheet, _numParticipants)
-    if _startRow == 0:
-      print("No games today! Pausing for 1000s")
-      time.sleep(1000)
+    try:
+      stats_dict = buildStatsDict(player_names_unique, url_date, current_season)
+    except timeout_decorator.TimeoutError:
+      print("NBA.com API not responding, retrying in 10 seconds...")
+      time.sleep(10)
       continue
-    else:
-      _playersCells = _getPlayersCells(_statsSheet, _startRow, _lastRow)
-  except gspread.exceptions.APIError:
-    print("API overloaded, adding a 100 second delay...")
-    time.sleep(100)
-    continue
-  except oauth2client.client.HttpAccessTokenRefreshError:
-    time.sleep(100)
-    continue
-
-  for _playerCell in _playersCells:
-  
-    while True:
+
+    update = False # only update the sheet if it's changed
     
-      try:
-        _playerName = _playerCell.value
-        print(_playerName)
-      except gspread.exceptions.APIError:
-        print("API overloaded, adding a 100 second delay...")
-        time.sleep(100)
-        continue
-        
-      try:
-        _firstName, _lastName = _getPlayerFirstNameLastName(_playerName)
-      except:
-        #_badName(_statsSheet, _playerCell)
-        break
-         
-      try:
-        print("Getting player ID...")
-        _playerID = _getPlayerID(_firstName, _lastName)
-      except timeout_decorator.TimeoutError:
-        print("NBA.com API not responding, retrying...")
-        continue
-      except:
-        #_badName(_statsSheet, _playerCell)
-        break
+    for player_cell in player_cells:
+      player_name = cleanPlayerName(player_cell)
+      player_stats_dict = checkStatsDict(player_name, stats_dict)
+      print("Updating " + player_name + "\'s stats locally")
+      todays_cells, update = updatePlayerStatsLocal(todays_cells, player_cell, player_stats_dict, update)
           
-      try:
-        print("Getting player stats...")
-        _playerStats = _getPlayerStats(_playerID, _urlDate)
-      except timeout_decorator.TimeoutError:
-        print("NBA.com API not responding, retrying...")
-        continue
+    if update == True:
+      while True:
+        try: 
+          print("Updating google sheet remotely...")
+          worksheet.update_cells(todays_cells)
+          break
+        except gspread.exceptions.APIError:
+          print("API overloaded, adding a 10 second delay...")
+          time.sleep(10)
+          continue
+    else:
+      print("No remote update necessary...")
+      time.sleep(30)
         
-      try: 
-        print("Updating stats...")
-        _updatePlayerStatsCells(_statsSheet, _playerCell, _playerStats)
-      except gspread.exceptions.APIError:
-        print("API overloaded, adding a 100 second delay...")
-        time.sleep(100)
-        continue
-      
-      break # move to next player in player list
-      
-  print("Cooling down, safe to break!")
-  time.sleep(100)
-  continue # restart entire loop
+    continue # restart entire loop
+
 

+ 8 - 0
requirements.txt

@@ -0,0 +1,8 @@
+gspread
+oauth2client
+datetime
+timeout-decorator
+requests
+time
+datetime
+git+git://github.com/swar/nba_api.git