a
    8ñ»jú¼  ã                   @   s  d Z ddlZddlmZmZ ddlmZ ddlmZ ddlm	Z	m
Z
mZ ddlZddlmZmZ dd	lmZmZmZmZmZ dd
lmZmZmZmZmZ ed ZdZddiZddddddœZ G dd„ deƒZ!ej"ej#dœdd„Z$e%ej# e%e& ej#dœdd„Z'ej#ej#dœdd„Z(dS )zScraper for http://fbref.com.é    N)ÚdatetimeÚtimezone)Úreduce)ÚPath)ÚCallableÚOptionalÚUnion)ÚetreeÚhtmlé   )ÚBaseRequestsReaderÚ
SeasonCodeÚadd_alt_team_namesÚmake_game_idÚstandardize_colnames)ÚDATA_DIRÚNOCACHEÚNOSTOREÚTEAMNAME_REPLACEMENTSÚloggerÚFBrefzhttps://fbref.comz	sec-ch-uaz@"Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"zITA-Serie AzFRA-Ligue 1zESP-La LigazENG-Premier LeaguezGER-Bundesliga)zSerie AzLigue 1zLa LigazPremier LeagueZ
Bundesligac                
       s  e Zd ZdZdddeeefeee	e
e	 f  eee	ee
f  eee	e
e	 eg e	f f  eeedœ‡ fdd„Zee
e	 dœdd„ƒZeee	e	f dœ‡ fd	d
„ƒZeedœdd„ƒZe	e	edœ‡ fdd„Zd2eejdœdd„Zd3eejdœdd„Zd4e	eejdœdd„Zd5e	eeee	e
e	 f  eejdœdd„Zd6e	ejdœdd „Zd7eejd!œd"d#„Ze j!e
e d$œd%d&„Z"d8e	eee	e
e	 f  eejd(œd)d*„Z#d9eee	e
e	 f  eejd+œd,d-„Z$d:eee	e
e	 f  eejd+œd.d/„Z%d;eee	e
e	 f  eejd+œd0d1„Z&‡  Z'S )<r   a`  Provides pd.DataFrames from data at http://fbref.com.

    Data will be downloaded as necessary and cached locally in
    ``~/soccerdata/data/FBref``.

    Parameters
    ----------
    leagues : string or iterable, optional
        IDs of leagues to include. For efficiently reading data from the Top-5
        European leagues, use "Big 5 European Leagues Combined".
    seasons : string, int or list, optional
        Seasons to include. Supports multiple formats.
        Examples: '16-17'; 2016; '2016-17'; [14, 15, 16]
    proxy : 'tor' or or dict or list(dict) or callable, optional
        Use a proxy to hide your IP address. Valid options are:
            - "tor": Uses the Tor network. Tor should be running in
              the background on port 9050.
            - str: The address of the proxy server to use.
            - list(str): A list of proxies to choose from. A different proxy will
              be selected from this list after failed requests, allowing rotating
              proxies.
            - callable: A function that returns a valid proxy. This function will
              be called after failed requests, allowing rotating proxies.
    no_cache : bool
        If True, will not use cached data.
    no_store : bool
        If True, will not store downloaded data.
    data_dir : Path
        Path to directory where data will be cached.
    N)ÚleaguesÚseasonsÚproxyÚno_cacheÚno_storeÚdata_dirc                    sT   t ƒ j|||||td� d| _|| _tt ¡ ƒ | j	¡rPd| j	vrPt
jddd� dS )zInitialize FBref reader.)r   r   r   r   r   Úheadersé   úBig 5 European Leagues CombinedzœYou are trying to scrape data for all of the Big 5 European leagues. This can be done more efficiently by setting leagues='Big 5 European Leagues Combined'.r   ©Ú
stacklevelN)ÚsuperÚ__init__ÚFBREF_HEADERSZ
rate_limitr   ÚsetÚBIG_FIVE_DICTÚvaluesÚissubsetr   ÚwarningsÚwarn)Úselfr   r   r   r   r   r   ©Ú	__class__© ú6E:\soccer\ml_env\Lib\site-packages\soccerdata/fbref.pyr#   D   s$    
úÿþüzFBref.__init__)Úreturnc                 C   s<   d| j v r.t ¡ D ]\}}|| j v r| j |= qt| j  ¡ ƒS )z"Return a list of selected leagues.r   )Z_leagues_dictr&   ÚitemsÚlistÚkeys)r+   Ú_Zstandardized_namer.   r.   r/   r   d   s
    


zFBref.leaguesc                    s   t ƒ  ¡ }| ddi¡ |S )zDReturn a dict mapping all canonical league IDs to source league IDs.r   )r"   Ú_all_leaguesÚupdate)ÚclsÚresr,   r.   r/   r5   m   s    
zFBref._all_leaguesc                 C   s   d| j v rtjS t | j ¡S )Nr   )r   r   Ú
MULTI_YEARZfrom_leagues)r+   r.   r.   r/   Ú_season_codet   s    
zFBref._season_code)ÚleagueÚseasonr0   c                    sL   |dkr>t t  |dd… d¡jddtjd�}t jtjd�|kS tƒ  ||¡S )	zCheck if a season is complete.r   éþÿÿÿNú%yr   r   )Útzinfo)Útz)r   ÚstrptimeÚyearr   ÚutcÚnowr"   Ú_is_complete)r+   r;   r<   Zseason_endsr,   r.   r/   rE   z   s    üzFBref._is_completeF)Úsplit_up_big5r0   c                 C   s  t › d�}| jd }|  ||¡}g }t |¡}| d¡D ]$}t|ƒ}| d¡|d< | |¡ q8t 	|¡ 
t¡jddid� 
| j¡jdd	� d¡ ¡ }	|	d
  | jj¡|	d
< |	d  | jj¡|	d< | j}
d| jv rô|rôtt| jƒdh tt ¡ ƒB ƒ}
|	|	j |
¡ S )a)  Retrieve selected leagues from the datasource.

        Parameters
        ----------
        split_up_big5: bool
            If True, it will load the "Big 5 European Leagues Combined" instead of
            each league individually.

        Returns
        -------
        pd.DataFrame
        z
/en/comps/zleagues.htmlz//table[contains(@id, 'comps')]z'.//th[@data-stat='league_name']/a/@hrefÚurlÚcompetition_namer;   ©Úcolumns)ÚsubsetZfirst_seasonZlast_seasonr   )Ú	FBREF_APIr   Úgetr
   ÚparseÚxpathÚ_parse_tableÚappendÚpdÚconcatÚpiper   ÚrenameÚ_translate_leagueÚdrop_duplicatesÚ	set_indexÚ
sort_indexÚapplyr:   r   r2   r%   r&   r'   ÚindexÚisin)r+   rF   rG   ÚfilepathÚreaderÚdfsÚtreeÚ
html_tableÚdf_tableÚdfr   r.   r.   r/   Úread_leagues†   s>    



ÿþýüûÿ	
ÿÿzFBref.read_leaguesc                 C   s8  d}|   |¡}g }| ¡ D ]¤\}}t|j }| j| |¡ }|  ||¡}	t |	¡}
|
 	d¡\}t
|ƒ}| 	d¡|d< ||d< d|jv r˜|jddidd	� d
|jv r¬d|d< nd|d< | |¡ qt |¡ t¡}|jddid�}|d  | jj¡|d< |jddgddd� | ddg¡ ¡ }|jtdƒ| jfddgf S )a2  Retrieve the selected seasons for the selected leagues.

        Parameters
        ----------
        split_up_big5: bool
            If True, it will load the "Big 5 European Leagues Combined" instead of
            each league individually.

        Returns
        -------
        pd.DataFrame
        zseasons_{}.htmlz//table[@id='seasons']z7//th[@data-stat='year_id' or @data-stat='year']/a/@hrefrG   zCompetition NameZYearZSeasonT)rJ   ÚinplaceÚFinalÚeliminationZFormatzround-robinrH   r;   rI   r<   Úfirst)rK   Zkeepre   NÚformat)rd   ÚiterrowsrL   rG   r   ri   rM   r
   rN   rO   rP   rJ   rU   rQ   rR   rS   rT   r   rZ   r:   rW   rX   rY   ÚlocÚslicer   )r+   rF   ÚfilemaskZ
df_leaguesr   Úlkeyr;   rG   r]   r^   r`   ra   rb   rc   r.   r.   r/   Úread_seasons³   s4    


ÿ


zFBref.read_seasonsÚstandard)Ú	stat_typeÚopponent_statsr0   c                 C   s  g d¢}d}||vr"t d|› �ƒ‚|dkr0d}n@|dkr>d}n2|dkrLd	}n$|d
kr^d}d}n|dkrld}n|}|r~|d7 }n|d7 }|  ¡ }g }| ¡ D �]:\\}}	}
|dk}|
d dk}| j| ||	|rÐ|n|¡ }td |
j d¡dd… ¡ |�rd|› d�n|�rd|› d�nd |
j d¡d  }|  	||¡}t
 |¡}| d|› d|› d�¡\}t|ƒ}||d< |	|d< | d¡|d< |�rÌ|jdddd � ¡  t¡|d< |jdddd!d"� |jd#ddd!d"� | |¡ qšt|ddgd$�jd%d&d'œd(� d%ti¡ g d)¢¡ ¡ S )*a÷  Retrieve aggregated season stats for all teams in the selected leagues and seasons.

        The following stat types are available:
            * 'standard'
            * 'keeper'
            * 'keeper_adv'
            * 'shooting'
            * 'passing'
            * 'passing_types'
            * 'goal_shot_creation'
            * 'defense'
            * 'possession'
            * 'playing_time'
            * 'misc'

        Parameters
        ----------
        stat_type: str
            Type of stats to retrieve.
        opponent_stats: bool
            If True, will retrieve opponent stats.

        Raises
        ------
        ValueError
            If ``stat_type`` is not valid.

        Returns
        -------
        pd.DataFrame
        ©rp   ÚkeeperÚ
keeper_advÚshootingÚpassingÚpassing_typesÚgoal_shot_creationÚdefenseÚ
possessionÚplaying_timeÚmisczteams_{}_{}_{}.htmlú)Invalid argument: stat_type should be in rp   Ústatsrt   Úkeepersru   Ú
keepersadvry   Úgcar|   ÚplayingtimeZ_againstZ_forr   ri   rg   ú/Néÿÿÿÿz/squads/z//table[@id='stats_teams_z' or @id='stats_squads_ú']r;   r<   z.//*[@data-stat='team']/a/@hrefrG   ÚCompr   ©ÚaxisÚlevelT©r‰   rŠ   re   ÚRk©ÚkeyÚteamZplayers_used)ÚSquadz# PlrI   ©r;   r<   r�   )Ú
ValueErrorro   rj   r   ri   rL   ÚjoinrG   ÚsplitrM   r
   rN   rO   rP   ÚxsÚsqueezeÚmapr&   ÚdroprQ   Ú_concatrU   Úreplacer   rX   rY   )r+   rq   rr   Ú
team_statsrm   Úpager   Úteamsrn   Úskeyr<   Úbig_fiveZ
tournamentr]   rG   r^   r`   ra   rb   r.   r.   r/   Úread_team_season_statsä   sp    "
ÿ&þýÿ
ÿÿÿþüÿzFBref.read_team_season_statsÚschedule)rq   rr   r�   Úforce_cacher0   c              	   C   sR  g d¢}d}||vr"t d|› �ƒ‚|dkr6|r6t dƒ‚|dkrBd}|rJdnd	}|  ¡ }|d
uršt|ƒ}	|j|jj|	dd�d
d
…f }
t|
ƒdkržt dƒ‚n|}
g }|
j ¡ D �]Þ\\}}}}| j	| 
|||¡ }t| d¡ƒdk�rt| dd¡d  d d d|› � }nŒt |¡tjk�r\tj |¡}d 
t |d
d… d¡jt |dd
… d¡j¡}ntj |¡}t| dd¡d  d|› � d d d|› � }|  ||¡ }| j|||�o¸| d�}t |¡}| d|› d�¡\}| d¡D ]}d|_�qæ| d¡D ]}| ¡  |¡ �qþt|ƒ}||d< ||d< dd„ | d ¡D ƒ|d!< d"d„ | d#¡D ƒ|d$< |jj}|dk�r‚|j d$d!gddd%�}| !|¡ q¬t"|g d&¢d'� #d(t$i¡j%d)d*id+� &| j'¡j&t(g d,¢d-�}t) *|d. ¡ +¡ |d.< |g d/¢  ,¡ }g d/¢|_|j-d0d1„ dd2�|d3< |j-d4d1„ dd2�|d5< |j-t.dd2�|d6< | /g d7¢¡ 0¡ j| j1 S )8aÃ  Retrieve the match logs for all teams in the selected leagues and seasons.

        The following stat types are available:
            * 'schedule'
            * 'keeper'
            * 'shooting'
            * 'passing'
            * 'passing_types'
            * 'goal_shot_creation'
            * 'defense'
            * 'possession'
            * 'misc'

        Parameters
        ----------
        stat_type: str
            Type of stats to retrieve.
        opponent_stats: bool
            If True, will retrieve opponent stats.
        team: str or list of str, optional
            Team(s) to retrieve. If None, will retrieve all teams.
        force_cache: bool
            By default no cached data is used for the current season.
            If True, will force the use of cached data anyway.

        Raises
        ------
        ValueError
            If ``stat_type`` is not valid.

        Returns
        -------
        pd.DataFrame
        )	r¡   rv   rt   rw   rx   ry   rz   r{   r}   zmatchlogs_{}_{}_{}.htmlr~   r¡   z=Opponent stats are not available for the 'schedule' stat typery   r‚   ZagainstÚforNé   )rŠ   r   z:No data found for the given teams in the selected seasons.r„   é   r   z
/matchlogsz
/all_compsz{}-{}r>   ©r   z//table[@id='matchlogs_r†   z%//th[@data-stat='header_for_against']Ú z//tfootr<   r�   c                 S   s   g | ]}|  d d¡‘qS )ZcskN)rM   )Ú.0Úxr.   r.   r/   Ú
<listcomp>×  s   z/FBref.read_team_match_stats.<locals>.<listcomp>z.//td[@data-stat='start_time']ÚTimec                 S   s<   g | ]4}|  d ¡r4|  d ¡d jdkr4|  d¡d nd‘qS ©z./ar   úMatch Reportz	./a/@hrefN©rO   Útext©r¨   Zmlinkr.   r.   r/   rª   Ú  s   ýÿÿú .//td[@data-stat='match_report']r­   rˆ   r‘   r�   ÚOpponentr‡   r;   rI   )	ZTeamr²   ZVenueÚDater«   ZRoundZDayÚResultr­   ©ÚcolsÚdate)r�   ÚopponentÚvenuer·   c                 S   s   | d dkr| d S | d S )Nr¹   ÚHomer�   r¸   r.   ©r©   r.   r.   r/   Ú<lambda>  ó    z-FBref.read_team_match_stats.<locals>.<lambda>©r‰   Ú	home_teamc                 S   s   | d dkr| d S | d S )Nr¹   ÚAwayr�   r¸   r.   r»   r.   r.   r/   r¼     r½   Ú	away_teamÚgame)r;   r<   r�   rÂ   )2r’   r    r   rk   r[   r\   ÚlenrG   r1   r   ri   r”   rL   Úrsplitr   Zfrom_leaguer9   rN   r   rA   rB   ZSINGLE_YEARrE   rM   r
   rO   r¯   Ú	getparentÚremoverP   rJ   Znlevelsr˜   rQ   r™   rš   r   rU   rT   rV   r   rR   Úto_datetimeÚffillÚcopyrZ   r   rX   rY   r   )r+   rq   rr   r�   r¢   r›   rm   Zopp_typeZdf_teamsZteams_to_checkÚiteratorr   rn   rž   Zteam_urlr]   rG   Z_skeyZseason_formatÚcurrent_seasonr^   r`   ra   Úelemrb   Z	nb_levelsrc   Zdf_tmpr.   r.   r/   Úread_team_match_statsY  sÄ    )
ÿþýüÿþÿþýüûÿ	

ÿ
ú

ÿþúù	öÿ
ÿ
ÿ
þüÿzFBref.read_team_match_stats)rq   r0   c                 C   sF  g d¢}d}||vr"t d|› �ƒ‚|dkr0d}n@|dkrBd}d}n.|dkrPd	}n |d
kr^d}n|dkrld}n|}|  ¡ }g }| ¡ D �]R\\}}}	|dk}
| j| |||¡ }td |	j d¡dd… ¡ d|› � |
rÜdnd |	j d¡d  }|  	||¡}t
 |¡}| d¡D ]}| ¡  |¡ �q|
�rpt|ƒ}|jdddd� ¡  t¡|d< ||d< |jddddd� nV| d|› d�¡\}tjdd�}t |j|¡ d|› d�¡\}t|ƒ}||d< ||d< t|ƒ}| |¡ q„t|dd gd!�}||jd"k }|jd#dd$d�jd%dd$d�jd&d'id(� d'ti¡j t!g d)¢d*� "g d+¢¡ #¡ S ),a�  Retrieve players from the datasource for the selected leagues and seasons.

        The following stat types are available:
            * 'standard'
            * 'shooting'
            * 'passing'
            * 'passing_types'
            * 'goal_shot_creation'
            * 'defense'
            * 'possession'
            * 'playing_time'
            * 'misc'
            * 'keeper'
            * 'keeper_adv'

        Parameters
        ----------
        stat_type :str
            Type of stats to retrieve.

        Raises
        ------
        TypeError
            If ``stat_type`` is not valid.

        Returns
        -------
        pd.DataFrame
        rs   zplayers_{}_{}_{}.htmlr~   rp   r   ry   r‚   r|   rƒ   rt   r€   ru   r�   r   r„   Nr…   z	/players/z#//td[@data-stat='comp_level']//spanr‡   r   rˆ   )zUnnamed: leaguer;   )zUnnamed: seasonr<   Tr‹   z"//comment()[contains(.,'div_stats_z')])Zrecoverz//table[contains(@id, 'stats_r;   r<   r�   ÚPlayerÚMatchesr   rŒ   r�   r�   rI   )rÎ   ÚNationÚPosÚAgeZBornrµ   )r;   r<   r�   Úplayer)$Ú	TypeErrorro   rj   r   ri   rL   r“   rG   r”   rM   r
   rN   rO   rÅ   rÆ   rP   r•   r–   r—   r&   r˜   r	   Ú
HTMLParserZ
fromstringr¯   Ú_fix_nation_colrQ   r™   rÎ   rU   rš   r   rT   r   rX   rY   )r+   rq   Zplayer_statsrm   rœ   r   Zplayersrn   rž   r<   rŸ   r]   rG   r^   r`   rÌ   rb   ÚelÚparserra   rc   r.   r.   r/   Úread_player_season_stats  s‚    ÿþ
ýüÿ
ÿ
ÿÿþýüûÿzFBref.read_player_season_stats)r¢   r0   c                 C   s°  | j dd�}g }| ¡ D ]ö\\}}}t|j }| jd|› d|› d� }|  ||¡}	t |	¡}
t|
 d¡d  d¡ }| jd	|› d|› d� }|  	||¡ }| j|||oª| d
�}	t |	¡}
|
 d¡d }t
|ƒ}dd„ | d¡D ƒ|d< ||d< ||d< |jdd�}| |¡ qt |¡jddddddœd� ttdœ¡ t¡}t |d ¡ ¡ |d< |jtdd�|d< |j|j ¡  d f j d!¡jd" |j|j ¡  d#f< | g d$¢¡ ¡ S )%aH  Retrieve the game schedule for the selected leagues and seasons.

        Parameters
        ----------
        force_cache : bool
             By default no cached data is used for the current season.
             If True, will force the use of cached data anyway.

        Returns
        -------
        pd.DataFrame
        T)rF   Zteams_r4   z.htmlz//a[text()='Scores & Fixtures']r   ÚhrefZ	schedule_r¦   z//table[contains(@id, 'sched')]c                 S   s<   g | ]4}|  d ¡r4|  d ¡d jdkr4|  d¡d nd‘qS r¬   r®   r°   r.   r.   r/   rª   ª  s   ýÿÿz'FBref.read_schedule.<locals>.<listcomp>r±   r­   r;   r<   Úall©ÚhowÚweekr¿   rÁ   Zhome_xgZaway_xg)ZWkrº   rÀ   ZxGzxG.1rI   )r¿   rÁ   r·   r   r¾   rÂ   Úmatch_reportr„   é   Úgame_id©r;   r<   rÂ   )ro   rj   rL   rG   r   rM   r
   rN   rO   rE   rP   ÚdropnarQ   rR   rS   rU   rš   r   rT   r   rÇ   rÈ   rZ   r   rk   rß   ÚisnaÚstrr”   rX   rY   )r+   r¢   r   r¡   rn   rž   r<   Z	url_statsZfilepath_statsr^   r`   Zurl_fixturesZfilepath_fixturesrË   ra   rb   rc   r.   r.   r/   Úread_schedule†  sZ    

ý
ú

ûþþõðÿ"ÿzFBref.read_schedule)r`   r0   c                 C   sJ   |  d¡dd… }g }|D ]*}| | d¡ d¡d |j ¡ dœ¡ q|S )zÕParse the teams from a match summary page.

        Parameters
        ----------
        tree : etree.ElementTree
            The match summary page.

        Returns
        -------
        list of dict
        z"//div[@class='scorebox']//strong/aNr¤   rÚ   r„   rà   )ÚidÚname)rO   rQ   rM   r”   r¯   Ústrip)r+   r`   Z
team_nodesr�   r�   r.   r.   r/   Ú_parse_teamsÐ  s
    (zFBref._parse_teamsÚsummary)rq   Úmatch_idr¢   r0   c                 C   sŽ  g d¢}t d }d}||vr*td|› �ƒ‚|  |¡ ¡ }||j ¡  |j ¡  @  }|dur’||j t	|t
ƒrt|gn|¡ }t|ƒdkr–tdƒ‚n|}g }	| ¡  ¡ D �]Œ\}
}| |d ¡}t d	|
d
 t|ƒ|d ¡ | j| |d ¡ }|  ||¡}t |¡}|  |¡\}}|dk�r dnd| }| d| |d ¡ d ¡}|du�ržt|ƒ}|d |d< |d |d< |d |d< |d |d< |d |d< |	 |¡ nt d|d ¡ | d| |d ¡ d ¡}|du�r$t|ƒ}|d |d< |d |d< |d |d< |d |d< |d |d< |	 |¡ q¦t d|d ¡ q¦t|	dgd�}||jj
 d¡  }|jddid� dti¡j t!g d¢d� "g d¢¡ #¡ S ) aÊ  Retrieve the match stats for the selected leagues and seasons.

        The following stat types are available:
            * 'summary'
            * 'keepers'
            * 'passing'
            * 'passing_types'
            * 'defense'
            * 'possession'
            * 'misc'

        Parameters
        ----------
        stat_type : str
            Type of stats to retrieve.
        match_id : int or list of int, optional
            Retrieve the event stream for a specific game.
        force_cache : bool
            By default no cached data is used to scrape the list of available
            games for the current season. If True, will force the use of
            cached data anyway.

        Raises
        ------
        ValueError
            If no games with the given IDs were found for the selected seasons and leagues.
        TypeError
            If ``stat_type`` is not valid.

        Returns
        -------
        pd.DataFrame
        )rë   r€   rw   rx   rz   r{   r}   ú/en/matches/{}úmatch_{}.htmlr~   Nr   ú:No games found with the given IDs in the selected seasons.rá   ú"[%s/%s] Retrieving game with id=%sr   r€   zkeeper_stats_{}z	stats_{}_ú//table[@id='rç   r†   rè   r�   rÂ   r;   r<   z0No stats found for home team for game with id=%sz0No stats found for away team for game with id=%sr�   z^\d+\sPlayers$ú#Újersey_numberrI   )rÎ   rÐ   rÑ   rÒ   ÚMinrµ   )r;   r<   rÂ   r�   rÓ   )$rL   rÔ   ræ   Úreset_indexrá   rä   rß   Úisnullr\   Ú
isinstancerå   rÃ   r’   rj   ri   r   Úinfor   rM   r
   rN   rê   ÚfindrP   rQ   Úwarningr™   rÎ   ÚcontainsrU   rš   r   rT   r   rX   rY   )r+   rq   rì   r¢   Zmatch_statsÚurlmaskrm   Údf_schedulerÊ   r   ÚirÂ   rG   r]   r^   r`   r¿   rÁ   Z	id_formatra   rb   rc   r.   r.   r/   Úread_player_match_statsâ  st    '
ÿ
ü


ÿþýÿzFBref.read_player_match_stats)rì   r¢   r0   c              	   C   sj  t d }d}|  |¡ ¡ }||j ¡  |j ¡  @  }|durt||j t|t	ƒrV|gn|¡ }t
|ƒdkrxtdƒ‚n|}g }| ¡  ¡ D �]Ê\}}	| |	d ¡}
t d|d t
|ƒ|	d ¡ | j| |	d ¡ }|  |
|¡}t |¡}|  |¡}| d	¡}t|ƒD �]N\}}t|ƒ}d
dg|_|| d |d< d|jjv �r²|j|jdk d }d|jd|…df< d|j|d…df< |	d |d< |	d |d< |	d |d< |	d |d< |j|dd� | dd || d ¡ d ¡}t|ƒ}|jddd�g d¢ }g d¢|_|d
   d¡|d
< |d
   d¡|d
< t!j"||dd
gdd�}|d   #d¡|d < | $|¡ �qqˆt! %|¡ &g d!¢¡S )"ab  Retrieve lineups for the selected leagues and seasons.

        Parameters
        ----------
        match_id : int or list of int, optional
            Retrieve the lineup for a specific game.
        force_cache : bool
            By default no cached data is used to scrape the list of available
            games for the current season. If True, will force the use of
            cached data anyway.

        Raises
        ------
        ValueError
            If no games with the given IDs were found for the selected seasons and leagues.

        Returns
        -------
        pd.DataFrame.
        rí   rî   Nr   rï   rá   rð   r   z//div[@class='lineup']ró   rÓ   rè   r�   ZBenchTZ
is_starterFrÂ   r;   r<   )re   rñ   zstats_{}_summaryrç   r†   r¾   )rÎ   rò   rÑ   rô   )rÓ   ró   ÚpositionÚminutes_playedZInt64Úleft)ÚonrÝ   r  râ   )'rL   ræ   rõ   rá   rä   rß   rö   r\   r÷   rå   rÃ   r’   rj   ri   r   rø   r   rM   r
   rN   rê   rO   Ú	enumeraterP   rJ   ró   r'   r[   rk   r˜   rù   Z	droplevelZastyperR   ÚmergeZfillnarQ   rS   rX   )r+   rì   r¢   rü   rm   rý   rÊ   Zlineupsrþ   rÂ   rG   r]   r^   r`   r�   Zhtml_tablesra   rb   Z	bench_idxZhtml_stats_tableZdf_stats_tabler.   r.   r/   Úread_lineupV  sh    ÿ
ü



ÿ
ÿzFBref.read_lineupc                 C   sZ  t d }d}|  |¡ ¡ }||j ¡  |j ¡  @  }|durt||j t|t	ƒrV|gn|¡ }t
|ƒdkrxtdƒ‚n|}g }| ¡  ¡ D �]Ž\}}	g }
| |	d ¡}t d|d t
|ƒ|	d ¡ | j| |	d ¡ }|  ||¡}t |¡}|  |¡}t|d	d
gƒD ]À\}}| d|› d�¡}|D ]ž}| d¡d j dd¡ ¡ }| d¡d j}| d¡d  ¡  ¡ }| d¡�r„| d¡d j}nd}| d¡d  d¡d }|
 |d |||||dœ¡ �q �qt |
¡}|	d |d< |	d |d< |	d |d< t
|ƒdk�r|jddd� | |¡ qˆt
|ƒdk�r0t ¡ S t  |¡ dt!i¡ "g d¢¡ #¡ j$dd �S )!a  Retrieve match events for the selected seasons or selected matches.

        The data returned includes the timing of goals, cards and substitutions.
        Also includes the players who are involved in the event.

        Parameters
        ----------
        match_id : int or list of int, optional
            Retrieve the events for a specific game.
        force_cache : bool
            By default no cached data is used to scrape the list of available
            games for the current season. If True, will force the use of
            cached data anyway.

        Raises
        ------
        ValueError
            If no games with the given IDs were found for the selected seasons and leagues.

        Returns
        -------
        pd.DataFrame.
        rí   rî   Nr   rï   rá   rð   r   ÚaÚbz/////*[@id='events_wrap']/div/div[@class='event r†   z./div[1]z&rsquor;r§   z./div[1]/small/spanz./div[2]/div[2]/divz./div[2]/div[2]/small/az./div[2]/div[1]/@classú rè   )r�   ÚminuteÚscoreÚplayer1Úplayer2Ú
event_typerÂ   r;   r<   r
  T)Zbyre   r�   râ   rÛ   rÜ   )%rL   ræ   rõ   rá   rä   rß   rö   r\   r÷   rå   rÃ   r’   rj   ri   r   rø   r   rM   r
   rN   rê   ÚziprO   r¯   rš   ré   Ztext_contentr”   rQ   rR   Ú	DataFrameZsort_valuesrS   r   rX   rY   rã   )r+   rì   r¢   rü   rm   rý   rÊ   Úeventsrþ   rÂ   Zmatch_eventsrG   r]   r^   r`   r�   r�   ÚtidZhtml_eventsÚer
  r  r  r  r  Zdf_match_eventsr.   r.   r/   Úread_events±  sz    ÿ
ü

úÿ


ÿþüÿzFBref.read_eventsc                 C   s   t d }d}|  |¡ ¡ }||j ¡  |j ¡  @  }|durt||j t|t	ƒrV|gn|¡ }t
|ƒdkrxtdƒ‚n|}g }| ¡  ¡ D ]¸\}}	| |	d ¡}
t d|d t
|ƒ|	d ¡ | j| |	d ¡ }|  |
|¡}t |¡}| d	¡}|du�r0t|ƒ}|	d
 |d
< |	d |d< |	d |d< | |¡ qˆt d|	d ¡ qˆt
|ƒdk�rXt ¡ S t|dgd�jddid� dti¡jtg d¢d�  g d¢¡ !¡ j"dd�S )aQ  Retrieve shooting data for the selected seasons or selected matches.

        The data returned includes who took the shot, when, with which body
        part and from how far away. Additionally, the player creating the
        chance and also the creation before this are included in the data.

        Parameters
        ----------
        match_id : int or list of int, optional
            Retrieve the shots for a specific game.
        force_cache : bool
            By default no cached data is used to scrape the list of available
            games for the current season. If True, will force the use of
            cached data anyway.

        Raises
        ------
        ValueError
            If no games with the given IDs were found for the selected seasons and leagues.

        Returns
        -------
        pd.DataFrame.
        rí   rî   Nr   rï   rá   rð   r   z//table[@id='shots_all']r;   r<   rÂ   z&No shot data found for game with id=%sr�   r�   r�   rI   )ZOutcomeZMinuteZDistancerÎ   z	Body PartZNotesÚEventrµ   râ   rÛ   rÜ   )#rL   ræ   rõ   rá   rä   rß   rö   r\   r÷   rå   rÃ   r’   rj   ri   r   rø   r   rM   r
   rN   rù   rP   rQ   rú   rR   r  r™   rU   rš   r   rT   r   rX   rY   rã   )r+   rì   r¢   rü   rm   rý   rÊ   Zshotsrþ   rÂ   rG   r]   r^   r`   ra   rb   r.   r.   r/   Úread_shot_events  s\    ÿ
ü


ÿþûñïÿzFBref.read_shot_events)F)F)rp   F)r¡   FNF)rp   )F)rë   NF)NF)NF)NF)(Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   ÚFBREF_DATADIRr   r   rå   r2   Úintr   Úboolr   r#   Úpropertyr   ÚclassmethodÚdictr5   r   r:   rE   rR   r  rd   ro   r    rÍ   rÙ   ræ   r	   ZElementTreerê   rÿ   r  r  r  Ú__classcell__r.   r.   r,   r/   r   $   s”   !ùù -2 ÿþw    ûú ;sJ   üûv  ýü]  ýüe  ýü)ra   r0   c                 C   s~   |   d¡D ]}tj| ¡ ddd� q
|   d¡D ]}| ¡  |¡ q.|   d¡D ]}| ¡  |¡ qLtjt | ¡dd�\}| 	¡ S )	z·Parse HTML table into a dataframe.

    Parameters
    ----------
    html_table : lxml.html.HtmlElement
        HTML table to clean up.

    Returns
    -------
    pd.DataFrame
    z//span[contains(@class, 'f-i')]ÚspanF)Z	with_tailz&//tbody/tr[contains(@class, 'spacer')]z%//tbody/tr[contains(@class, 'thead')]Úlxml)Zflavor)
rO   r	   Zstrip_elementsrÅ   rÆ   rR   Z	read_htmlr
   ZtostringZconvert_dtypes)ra   rÌ   rb   r.   r.   r/   rP   q  s    rP   )r_   rŽ   r0   c           	      C   sÐ  g }t | dd„ dd�} | D ]Ú}t |j ¡ ¡}|jddddd� |jd d	kr|jd
ddd� t |d ¡}|j|ddgf j	|j|ddgf< | 
| ¡ ¡ t |d ¡}|j|ddgf j	|j|ddgf< d
|j|df< tj |jdd� ¡ ¡|_qt|ƒ�rô|d jd d	k�rôt|ƒD ]Ö\}}|d  |d d ¡�s|d j|ddd�}tjdj| d jdd… | j	| | jdd… | j	d tt|j|d dkddgf jdd� ¡ ƒ¡d tt|j|d dkddgf jdd� ¡ ƒ¡d�dd� �qt|ƒ�rÆ|d jd d	k�rÆtdd„ |ƒ}t |d ¡}|j|ddgf j	|j|ddgf< d
|j|df< tj |jdd� ¡ ¡}t| ƒD ]F\}}|j |¡�r”t|jƒt|ƒk�r°||_n|j|dd�| |< �q~t | ¡S )a9  Merge matching tables scraped from different pages.

    The level 0 headers are not consistent across seasons and leagues, this
    function tries to determine uniform column names.

    If there are dataframes with different columns, we will use the ones from
    the dataframe with the most columns.

    Parameters
    ----------
    dfs : list(pd.DataFrame)
        Input dataframes.
    key : list(str)
        List of columns that uniquely identify each df.

    Returns
    -------
    pd.DataFrame
        Concatenated dataframe with uniform column names.
    c                 S   s
   t | jƒS ©N)rÃ   rJ   r»   r.   r.   r/   r¼   £  r½   z_concat.<locals>.<lambda>T)rŽ   Úreversez^Unnamed:.*N)Ú
to_replaceÚvalueÚregexre   r   r¤   r§   )r&  r'  re   r   F)r[   Úouter)Z	indicatorrÝ   zêDifferent columns found for {first} and {cur}.

The following columns are missing in {first}: {extra_cols}.

The following columns are missing in {cur}: {missing_cols}.

The columns of the dataframe with the most columns will be used.z, Ú_mergeÚ	left_onlyÚ
right_only)rh   ÚcurZ
extra_colsZmissing_colsr    c                 S   s
   |   |¡S r$  )Zcombine_first)r  Úrightr.   r.   r/   r¼   Þ  r½   )rJ   Z
fill_value)ÚsortedrR   r  rJ   Útolistrš   Úshaperö   rk   r'   rQ   rÉ   Z
MultiIndexÚfrom_tuplesZ
to_recordsrÃ   r  Úequalsr  r)   r*   ri   Zilocr“   r—   rå   r   ZreindexrS   )	r_   rŽ   Zall_columnsrc   rJ   Úmaskrþ   r8   Z
column_idxr.   r.   r/   r™   ‹  sl    ""ÿÿþÿÿþÿðæ
"r™   )rb   r0   c              	   C   sf   d| j  d¡vrb| jdddd� ¡  dd„ ¡| jdd…tdƒdff< |  dd	| jdddd� ¡ ¡ | S )
zêFix the "Nation" column.

    Adds a 'nations' column for international games based on the team's name.

    Parameters
    ----------
    df_table : pd.DataFrame
        Input dataframe.

    Returns
    -------
    pd.DataFrame
    rÐ   r   r�   rˆ   c                 S   s   t | tƒr| dkr| S d S )Nr�   )r÷   rå   r»   r.   r.   r/   r¼   	  r½   z!_fix_nation_col.<locals>.<lambda>Nr¤   )zUnnamed: nationrÐ   )rJ   Zget_level_valuesr•   r–   rZ   rk   rl   Úinsert)rb   r.   r.   r/   rÖ   ÷  s    þÿýrÖ   ))r  r)   r   r   Ú	functoolsr   Úpathlibr   Útypingr   r   r   ZpandasrR   r#  r	   r
   Ú_commonr   r   r   r   r   Ú_configr   r   r   r   r   r  rL   r$   r&   r   ZHtmlElementr  rP   r2   rå   r™   rÖ   r.   r.   r.   r/   Ú<module>   s>   ÿû	        Ul