Source code for nhlscrapi.scrapr.eventsummrep

from itertools import chain

from nhlscrapi._tools import (
    to_int,
#    re_comp_num_pos_name,
    exclude_from as ex_junk
)
from nhlscrapi.scrapr.reportloader import ReportLoader


def _rem(txt):
    return ex_junk(txt, containing=['\n','\r'])
    
    
def _zip_top_bot(txt_lst):
    cols = len(txt_lst)/2
    return [ (k,v) for k, v in zip(txt_lst[:cols],txt_lst[cols:]) ]
    

class EventSummRep(ReportLoader):
[docs] """Retrieve and load event summary report from nhl.com""" def __init__(self, game_key): super(EventSummRep, self).__init__(game_key, 'event_summary') self.shots = { } """ The shot summary by strength at the aggregate and detail level :returns: dict of the form .. code:: python { 'home/away': { 'agg': { 'ev/pp/sh/tot': { 'g': goals, 's': shots } }, 'det': { '5v5/5v4/5v3/et c': { 'g': goals, 's': shots } } } } """ self.face_offs = { } """ Face off summary by strength. :returns: dict of the form .. code:: python { 'home/away': { 'ev/pp/sh/tot': { 'won': goals, 'total': shots } }, } } """ self.by_team = { } """ By player team summary. :returns: dict of the form .. code:: python { 'home/away': { 'num': { 'pos': pos, 'name': { 'first': first, 'last': last }, 'g/a/p/pm/pn/pim/shifts/s/ab/ms/ht/gv/tk/bs': value 'fo': { 'won': won, 'tot': total }, 'toi': { 'tot/avg/pp/sh/ev': { 'min': mins, 'sec': secs } } } } } """ # define place holders for different parts of the report # each one corresponds to a bit of data that can be parsed individually self.__aw_top, self.__aw_bot, self.__h_top, self.__h_bot = [None]*4 # shot summ self.__away_fo, self.__home_fo = [None]*2 # face off summ def parse(self):
[docs] """ Retreive and parse Event Summary report for the given :py:class:`nhlscrapi.games.game.GameKey` :returns: ``self`` on success, ``None`` otherwise """ try: return super(EventSummRep, self).parse() \ .parse_away_shots() \ .parse_home_shots() \ .parse_away_fo() \ .parse_home_fo() \ .parse_away_by_player() \ .parse_home_by_player() except: return None def __get_tr_by_name(self, name):
xp = ".//td[contains(./text(),'{}')]/../following-sibling::tr".format(name) return self.html_doc().xpath(xp)[0] def __set_shot_tables(self): if self.__aw_top is None: shot_tr = self.__get_tr_by_name('SHOTS SUMM') _ , self.__aw_top, self.__aw_bot, self.__home_top, self.__home_bot = shot_tr.xpath('.//table') def __parse_shot_tables(self, top_table, bot_table): def key_g_s(rows_lst): res = { } for k, v in _zip_top_bot(_rem(rows_lst)): g, s = v.split('-') if '-' in v else ('0', '0') res[k.lower()] = { 'g': to_int(g, 0), 's': to_int(s, 0) } return res return { 'agg': key_g_s(top_table.xpath('.//text()')), 'det': key_g_s(bot_table.xpath('.//text()')) } def __set_fo_tables(self): if self.__away_fo is None: fo_tr = self.__get_tr_by_name('FACE-OFF') _, self.__away_fo, self.__home_fo = fo_tr.xpath('.//table') def __parse_fo_table(self, table): def str_w_t(rows_lst): res = { } for k, v in _zip_top_bot(_rem(rows_lst)): ct, _ = v.split('/') if '/' in v else ('0-0','0') w, t = ct.split('-') if '-' in v else ('0', '0') res[k.lower()] = { 'won': to_int(w, 0), 'total': to_int(t, 0) } return res return str_w_t(table.xpath('.//text()')) def __set_team_tables(self): if self.__away is None: team_tr = self.__get_tr_by_name('TEAM') _, self.__away, self.__home = team_tr.xpath('.//table') def __parse_team_tables(self, table): pass def parse_home_shots(self):
[docs] """ Parse shot info for home team. :returns: ``self`` on success, ``None`` otherwise """ try: self.__set_shot_tables() self.shots['home'] = self.__parse_shot_tables( self.__home_top, self.__home_bot ) return self except: return None def parse_away_shots(self):
[docs] """ Parse shot info for away team. :returns: ``self`` on success, ``None`` otherwise """ try: self.__set_shot_tables() self.shots['away'] = self.__parse_shot_tables( self.__aw_top, self.__aw_bot ) return self except: return None def parse_home_fo(self):
[docs] """ Parse face-off info for home team. :returns: ``self`` on success, ``None`` otherwise """ try: self.__set_fo_tables() self.face_offs['home'] = self.__parse_fo_table(self.__home_fo) return self except: return None def parse_away_fo(self):
[docs] """ Parse face-off info for away team. :returns: ``self`` on success, ``None`` otherwise """ try: self.__set_fo_tables() self.face_offs['away'] = self.__parse_fo_table(self.__away_fo) return self except: return None def __read_line(self, tr):
rec = _rem(tr.xpath('.//text()')) if len(rec) == 25: # player info num = to_int(rec[0],0) if not num: return { } dat = { } dat['pos'] = rec[1] last, first = rec[2].split(',') dat['name'] = { 'first': first, 'last': last } dat['shifts'] = to_int(rec[10],0) cols = chain( [ (i+3,v) for i,v in enumerate(['g','a','p','pm','pn','pim']) ], [ (i+15,v) for i,v in enumerate(['s','ab','ms','ht','gv','tk','bs']) ] ) for i, col in cols: dat[col] = to_int(rec[i],0) dat['toi'] = { } for k, v in [ (9,'tot'), (11,'avg'), (12,'pp'), (13,'sh'), (14,'ev') ]: if ':' in rec[k]: mins, secs = rec[k].split(':') dat['toi'][v] = { 'min': to_int(mins,0), 'sec': to_int(secs,0) } else: dat['toi'][v] = { 'min': 0, 'sec': 0 } w, l = to_int(rec[22],0), to_int(rec[23],0) dat['fo'] = { 'won': w, 'total': w+l } return num, dat else: return -1, { } def __parse_players(self): bp_tr = self.__get_tr_by_name('TEAM SUMM') all_bp = bp_tr.xpath(".//tr[contains(@class,'Color')]") t = 'away' self.by_team = { 'home': { }, 'away': { } } for abp in all_bp: num, p = self.__read_line(abp) if num == -1: t = 'home' else: self.by_team[t][num] = p def parse_home_by_player(self):
[docs] """ Parse by player info for home team. :returns: ``self`` on success, ``None`` otherwise """ try: if not self.by_team: self.__parse_players() return self except: return None def parse_away_by_player(self):
[docs] """ Parse by player info for away team. :returns: ``self`` on success, ``None`` otherwise """ try: if not self.by_team is None: self.__parse_players() return self except: return None