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