Source code for nhlscrapi.scrapr.toirep

from nhlscrapi._tools import to_int
from nhlscrapi._tools import exclude_from as ex_junk

from nhlscrapi.scrapr.reportloader import ReportLoader
from nhlscrapi.games.events import EventType as ET


class TOIRepBase(ReportLoader):
[docs] """ Scrapes TOI reports. (home/away are same format). """ def __init__(self, game_key, rep_type): super(TOIRepBase, self).__init__(game_key, rep_type) self.by_player = { } """ By player dictionary of shift summaries. The only events recorded per shift are :py:class:`.EventType.Goal` or :py:class:`.EventType.Penalty`. For ``period = 0``, the game totals are returned. Format is .. code:: python { player_num: { 'player_name': { 'first': '', 'last': '' }, 'shifts': [ { 'shift_num': shift_num, 'period': period_num, 'start': start_time (elapsed) 'end': end_time (elapsed) 'dur': length_of_shift, 'event': event_enum_goal_or_penalty } ], 'by_period': { 'period': period_num, 'shifts': shift_count, 'avg': { 'min': min, 'sec': sec }, 'toi': { 'min': min, 'sec': sec }, 'ev_toi': { 'min': min, 'sec': sec }, 'pp_toi': { 'min': min, 'sec': sec }, 'sh_toi': { 'min': min, 'sec': sec } } } } """ def __player_shifts(self, shift): parsed_shifts = [] while True: sh_arr = ex_junk(shift.xpath('.//text()'), ['\r','\n'], ['']) parsed_shifts.append(self.__build_shift(sh_arr)) # get next row shift = shift.xpath('following-sibling::tr')[0] cl = shift.get('class') if cl is None or cl.strip() not in ['oddColor', 'evenColor']: break return parsed_shifts, shift def __get_time(self, time_str): mins, secs = time_str.split(':') return { 'min': to_int(mins), 'sec': to_int(secs) } def __build_shift(self, shift): shift = [s.strip() for s in shift] ev = None if shift[-1] == 'G': ev = ET.Goal elif shift[-1] == 'P': ev = ET.Penalty return { 'shift_num': to_int(shift[0]), 'period': 4 if shift[1] == 'OT' else to_int(shift[1]), 'start': self.__get_time(shift[2].split(' / ')[0]), 'end': self.__get_time(shift[3].split(' / ')[0]), 'dur': self.__get_time(shift[4]), 'event': ev } def __get_by_per_summ(self, per_summ): summ = { } while True: cl = per_summ.get('class') if cl is not None and cl.strip() in ['oddColor', 'evenColor']: txt = ex_junk(per_summ.xpath('.//text()'), ['\r', '\n'], ['']) if txt: per = to_int(txt[0]) per = per if per > 0 else 4 if txt[0] == 'OT' else 0 ps = { 'shifts': to_int(txt[1]), 'avg': self.__get_time(txt[2]), 'toi': self.__get_time(txt[3]), 'ev_toi': self.__get_time(txt[4]), 'pp_toi': self.__get_time(txt[5]), 'sh_toi': self.__get_time(txt[6]) } summ[per] = ps per_summ = per_summ.xpath('following-sibling::tr') if per_summ: per_summ = per_summ[0] else: break return summ, per_summ def parse(self):
[docs] """ Parse full TOI document. :returns: ``self`` if successful else ``None`` """ try: return super(TOIRepBase, self).parse().self.parse_shifts() except: return None def parse_shifts(self):
[docs] """ Parse shifts from TOI report :returns: self if successfule else None """ lx_doc = self.html_doc() pl_heads = lx_doc.xpath('//td[contains(@class, "playerHeading")]') for pl in pl_heads: sh_sum = { } pl_text = pl.xpath('text()')[0] num_name = pl_text.replace(',','').split(' ') sh_sum['player_num'] = int(num_name[0]) if num_name[0].isdigit() else -1 sh_sum['player_name'] = { 'first': num_name[2], 'last': num_name[1] } first_shift = pl.xpath('../following-sibling::tr')[1] sh_sum['shifts'], last_shift = self.__player_shifts(first_shift) while ('Per' not in last_shift.xpath('.//text()')): last_shift = last_shift.xpath('following-sibling::tr')[0] per_summ = last_shift.xpath('.//tr')[0] sh_sum['by_period'], last_sum = self.__get_by_per_summ(per_summ) self.by_player[sh_sum['player_num']] = sh_sum return self if self.by_player else None class HomeTOIRep(TOIRepBase):
[docs] """Scrapes the home team TOI report""" def __init__(self, game_key): super(HomeTOIRep, self).__init__(game_key, "home_toi") class AwayTOIRep(TOIRepBase):
[docs] """Scrapes the home team TOI report""" def __init__(self, game_key): super(AwayTOIRep, self).__init__(game_key, "away_toi")