In [ ]:
import requests
from bs4 import BeautifulSoup
import pandas as pd
In [ ]:
standing_url = "https://fbref.com/en/comps/9/Premier-League-Stats"
In [ ]:
data = requests.get(standing_url)
In [ ]:
soup = BeautifulSoup(data.text)
In [ ]:
standing_table = soup.select('table.stats_table')[0]
In [ ]:
links = standing_table.find_all('a')
links = [l.get("href") for l in links]
links = [l for l in links if '/squads' in l]
links
Out[ ]:
['/en/squads/b8fd03ef/Manchester-City-Stats',
 '/en/squads/18bb7c10/Arsenal-Stats',
 '/en/squads/19538871/Manchester-United-Stats',
 '/en/squads/b2b47a98/Newcastle-United-Stats',
 '/en/squads/822bd0ba/Liverpool-Stats',
 '/en/squads/d07537b9/Brighton-and-Hove-Albion-Stats',
 '/en/squads/8602292d/Aston-Villa-Stats',
 '/en/squads/361ca564/Tottenham-Hotspur-Stats',
 '/en/squads/cd051869/Brentford-Stats',
 '/en/squads/fd962109/Fulham-Stats',
 '/en/squads/47c64c55/Crystal-Palace-Stats',
 '/en/squads/cff3d9bb/Chelsea-Stats',
 '/en/squads/8cec06e1/Wolverhampton-Wanderers-Stats',
 '/en/squads/7c21e445/West-Ham-United-Stats',
 '/en/squads/4ba7cbea/Bournemouth-Stats',
 '/en/squads/e4a775cb/Nottingham-Forest-Stats',
 '/en/squads/d3fd31cc/Everton-Stats',
 '/en/squads/a2d435b3/Leicester-City-Stats',
 '/en/squads/5bfb9659/Leeds-United-Stats',
 '/en/squads/33c895d4/Southampton-Stats']
turning the href values to links¶
In [ ]:
team_urls = [f"https://fbref.com{l}" for l in links]
team_urls
Out[ ]:
['https://fbref.com/en/squads/b8fd03ef/Manchester-City-Stats',
 'https://fbref.com/en/squads/18bb7c10/Arsenal-Stats',
 'https://fbref.com/en/squads/19538871/Manchester-United-Stats',
 'https://fbref.com/en/squads/b2b47a98/Newcastle-United-Stats',
 'https://fbref.com/en/squads/822bd0ba/Liverpool-Stats',
 'https://fbref.com/en/squads/d07537b9/Brighton-and-Hove-Albion-Stats',
 'https://fbref.com/en/squads/8602292d/Aston-Villa-Stats',
 'https://fbref.com/en/squads/361ca564/Tottenham-Hotspur-Stats',
 'https://fbref.com/en/squads/cd051869/Brentford-Stats',
 'https://fbref.com/en/squads/fd962109/Fulham-Stats',
 'https://fbref.com/en/squads/47c64c55/Crystal-Palace-Stats',
 'https://fbref.com/en/squads/cff3d9bb/Chelsea-Stats',
 'https://fbref.com/en/squads/8cec06e1/Wolverhampton-Wanderers-Stats',
 'https://fbref.com/en/squads/7c21e445/West-Ham-United-Stats',
 'https://fbref.com/en/squads/4ba7cbea/Bournemouth-Stats',
 'https://fbref.com/en/squads/e4a775cb/Nottingham-Forest-Stats',
 'https://fbref.com/en/squads/d3fd31cc/Everton-Stats',
 'https://fbref.com/en/squads/a2d435b3/Leicester-City-Stats',
 'https://fbref.com/en/squads/5bfb9659/Leeds-United-Stats',
 'https://fbref.com/en/squads/33c895d4/Southampton-Stats']

Extracting match statistics using pandas and requests

  1. exploring team 1 data
In [ ]:
team1_url = team_urls[0]
t1_data = requests.get(team1_url)
In [ ]:
matches = pd.read_html(t1_data.text, match="Scores & Fixtures")
matches[0]
Out[ ]:
Date Time Comp Round Day Venue Result GF GA Opponent xG xGA Poss Attendance Captain Formation Referee Match Report Notes
0 2022-07-30 17:00 Community Shield FA Community Shield Sat Neutral L 1.0 3.0 Liverpool NaN NaN 57.0 NaN Rúben Dias 4-3-3 Craig Pawson Match Report NaN
1 2022-08-07 16:30 Premier League Matchweek 1 Sun Away W 2.0 0.0 West Ham 2.2 0.5 75.0 62443.0 İlkay Gündoğan 4-3-3 Michael Oliver Match Report NaN
2 2022-08-13 15:00 Premier League Matchweek 2 Sat Home W 4.0 0.0 Bournemouth 1.7 0.1 67.0 53453.0 İlkay Gündoğan 4-2-3-1 David Coote Match Report NaN
3 2022-08-21 16:30 Premier League Matchweek 3 Sun Away D 3.0 3.0 Newcastle Utd 2.1 1.8 69.0 52258.0 İlkay Gündoğan 4-3-3 Jarred Gillett Match Report NaN
4 2022-08-27 15:00 Premier League Matchweek 4 Sat Home W 4.0 2.0 Crystal Palace 2.2 0.1 74.0 53112.0 Kevin De Bruyne 4-2-3-1 Darren England Match Report NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
56 2023-05-21 16:00 Premier League Matchweek 37 Sun Home W 1.0 0.0 Chelsea 1.2 1.2 64.0 53490.0 Kyle Walker 3-4-3◆ Michael Oliver Match Report NaN
57 2023-05-24 20:00 Premier League Matchweek 32 Wed Away D 1.0 1.0 Brighton 1.8 2.2 60.0 31388.0 İlkay Gündoğan 4-3-3 Simon Hooper Match Report NaN
58 2023-05-28 16:30 Premier League Matchweek 38 Sun Away L 0.0 1.0 Brentford 1.6 1.3 65.0 17120.0 Kyle Walker 3-2-4-1 John Brooks Match Report NaN
59 2023-06-03 15:00 FA Cup Final Sat Home W 2.0 1.0 Manchester Utd NaN NaN 60.0 83179.0 İlkay Gündoğan 3-2-4-1 Paul Tierney Match Report NaN
60 2023-06-10 22:00 Champions Lg Final Sat Neutral NaN NaN NaN it Inter NaN NaN NaN NaN NaN NaN NaN Head-to-Head NaN

61 rows × 19 columns

Getting match Shooting stats

In [ ]:
soup = BeautifulSoup(t1_data.text)

links = soup.find_all('a')
links = [l.get('href') for l in links if 'Scores & Fixtures' in l]
fixture_data = [f"https://fbref.com{l}" for l in links]
fixture_data
Out[ ]:
['https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/all_comps/schedule/Manchester-City-Scores-and-Fixtures-All-Competitions',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c9/schedule/Manchester-City-Scores-and-Fixtures-Premier-League',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c8/schedule/Manchester-City-Scores-and-Fixtures-Champions-League',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c514/schedule/Manchester-City-Scores-and-Fixtures-FA-Cup',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c690/schedule/Manchester-City-Scores-and-Fixtures-EFL-Cup',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c602/schedule/Manchester-City-Scores-and-Fixtures-FA-Community-Shield',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/all_comps/schedule/Manchester-City-Scores-and-Fixtures-All-Competitions',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c9/schedule/Manchester-City-Scores-and-Fixtures-Premier-League',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c8/schedule/Manchester-City-Scores-and-Fixtures-Champions-League',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c514/schedule/Manchester-City-Scores-and-Fixtures-FA-Cup',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c690/schedule/Manchester-City-Scores-and-Fixtures-EFL-Cup',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c602/schedule/Manchester-City-Scores-and-Fixtures-FA-Community-Shield',
 'https://fbref.com#all_matchlogs',
 'https://fbref.comNone',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/all_comps/schedule/Manchester-City-Scores-and-Fixtures-All-Competitions',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c9/schedule/Manchester-City-Scores-and-Fixtures-Premier-League',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c8/schedule/Manchester-City-Scores-and-Fixtures-Champions-League',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c514/schedule/Manchester-City-Scores-and-Fixtures-FA-Cup',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c690/schedule/Manchester-City-Scores-and-Fixtures-EFL-Cup',
 'https://fbref.com/en/squads/b8fd03ef/2022-2023/matchlogs/c602/schedule/Manchester-City-Scores-and-Fixtures-FA-Community-Shield',
 'https://fbref.com/en/matches/']
In [ ]:
fixture_data_url = fixture_data[0]
fixture_data = requests.get(fixture_data_url)
In [ ]:
soup = BeautifulSoup(fixture_data.text)

fixture_links = soup.find_all('a')
fixture_links = [l.get('href') for l in fixture_links]
fixture_links = [l for l in fixture_links if l and 'all_comps/shooting' in l]
In [ ]:
shooting_data = requests.get(f"https://fbref.com{fixture_links[0]}")
In [ ]:
shooting_stats = pd.read_html(shooting_data.text, match="Shooting")
shooting_stats = shooting_stats[0]
shooting_stats
Out[ ]:
For Manchester City ... Standard Expected Unnamed: 25_level_0
Date Time Comp Round Day Venue Result GF GA Opponent ... Dist FK PK PKatt xG npxG npxG/Sh G-xG np:G-xG Match Report
0 2022-07-30 17:00 Community Shield FA Community Shield Sat Neutral L 1 3 Liverpool ... NaN NaN 0 0 NaN NaN NaN NaN NaN Match Report
1 2022-08-07 16:30 Premier League Matchweek 1 Sun Away W 2 0 West Ham ... 18.7 1.0 1 1 2.2 1.4 0.11 -0.2 -0.4 Match Report
2 2022-08-13 15:00 Premier League Matchweek 2 Sat Home W 4 0 Bournemouth ... 17.5 0.0 0 0 1.7 1.7 0.09 1.3 1.3 Match Report
3 2022-08-21 16:30 Premier League Matchweek 3 Sun Away D 3 3 Newcastle Utd ... 16.2 1.0 0 0 2.1 2.1 0.10 0.9 0.9 Match Report
4 2022-08-27 15:00 Premier League Matchweek 4 Sat Home W 4 2 Crystal Palace ... 14.1 0.0 0 0 2.2 2.2 0.13 1.8 1.8 Match Report
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
56 2023-05-21 16:00 Premier League Matchweek 37 Sun Home W 1 0 Chelsea ... 18.8 0.0 0 0 1.2 1.2 0.08 -0.2 -0.2 Match Report
57 2023-05-24 20:00 Premier League Matchweek 32 Wed Away D 1 1 Brighton ... 13.9 0.0 0 0 1.8 1.8 0.14 -0.8 -0.8 Match Report
58 2023-05-28 16:30 Premier League Matchweek 38 Sun Away L 0 1 Brentford ... 16.8 0.0 0 0 1.6 1.6 0.11 -1.6 -1.6 Match Report
59 2023-06-03 15:00 FA Cup Final Sat Home W 2 1 Manchester Utd ... NaN NaN 0 0 NaN NaN NaN NaN NaN Match Report
60 NaN NaN NaN NaN NaN NaN 43-10-7 150 46 NaN ... 16.8 24.0 14 18 104.2 92.8 0.12 42.8 40.2 NaN

61 rows × 26 columns

Cleaning and merging Scraped data¶

 droping the top level index
In [ ]:
shooting_stats.columns = shooting_stats.columns.droplevel()
shooting_stats
Out[ ]:
Date Time Comp Round Day Venue Result GF GA Opponent ... Dist FK PK PKatt xG npxG npxG/Sh G-xG np:G-xG Match Report
0 2022-07-30 17:00 Community Shield FA Community Shield Sat Neutral L 1 3 Liverpool ... NaN NaN 0 0 NaN NaN NaN NaN NaN Match Report
1 2022-08-07 16:30 Premier League Matchweek 1 Sun Away W 2 0 West Ham ... 18.7 1.0 1 1 2.2 1.4 0.11 -0.2 -0.4 Match Report
2 2022-08-13 15:00 Premier League Matchweek 2 Sat Home W 4 0 Bournemouth ... 17.5 0.0 0 0 1.7 1.7 0.09 1.3 1.3 Match Report
3 2022-08-21 16:30 Premier League Matchweek 3 Sun Away D 3 3 Newcastle Utd ... 16.2 1.0 0 0 2.1 2.1 0.10 0.9 0.9 Match Report
4 2022-08-27 15:00 Premier League Matchweek 4 Sat Home W 4 2 Crystal Palace ... 14.1 0.0 0 0 2.2 2.2 0.13 1.8 1.8 Match Report
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
56 2023-05-21 16:00 Premier League Matchweek 37 Sun Home W 1 0 Chelsea ... 18.8 0.0 0 0 1.2 1.2 0.08 -0.2 -0.2 Match Report
57 2023-05-24 20:00 Premier League Matchweek 32 Wed Away D 1 1 Brighton ... 13.9 0.0 0 0 1.8 1.8 0.14 -0.8 -0.8 Match Report
58 2023-05-28 16:30 Premier League Matchweek 38 Sun Away L 0 1 Brentford ... 16.8 0.0 0 0 1.6 1.6 0.11 -1.6 -1.6 Match Report
59 2023-06-03 15:00 FA Cup Final Sat Home W 2 1 Manchester Utd ... NaN NaN 0 0 NaN NaN NaN NaN NaN Match Report
60 NaN NaN NaN NaN NaN NaN 43-10-7 150 46 NaN ... 16.8 24.0 14 18 104.2 92.8 0.12 42.8 40.2 NaN

61 rows × 26 columns

Combining our mathes df and our shooting df

In [ ]:
team_stats = matches[0].merge(shooting_stats[["Date", "Sh", "SoT", "Dist", "FK", "PK", "PKatt"]], on="Date")
team_stats.head()
Out[ ]:
Date Time Comp Round Day Venue Result GF GA Opponent ... Formation Referee Match Report Notes Sh SoT Dist FK PK PKatt
0 2022-07-30 17:00 Community Shield FA Community Shield Sat Neutral L 1.0 3.0 Liverpool ... 4-3-3 Craig Pawson Match Report NaN 14 8 NaN NaN 0 0
1 2022-08-07 16:30 Premier League Matchweek 1 Sun Away W 2.0 0.0 West Ham ... 4-3-3 Michael Oliver Match Report NaN 13 1 18.7 1.0 1 1
2 2022-08-13 15:00 Premier League Matchweek 2 Sat Home W 4.0 0.0 Bournemouth ... 4-2-3-1 David Coote Match Report NaN 19 7 17.5 0.0 0 0
3 2022-08-21 16:30 Premier League Matchweek 3 Sun Away D 3.0 3.0 Newcastle Utd ... 4-3-3 Jarred Gillett Match Report NaN 21 10 16.2 1.0 0 0
4 2022-08-27 15:00 Premier League Matchweek 4 Sat Home W 4.0 2.0 Crystal Palace ... 4-2-3-1 Darren England Match Report NaN 18 5 14.1 0.0 0 0

5 rows × 25 columns

In [ ]:
print(team_data.shape)
print(matches[0].shape)
print(shooting_stats.shape)
(60, 25)
(61, 19)
(61, 26)

Using Loops to query multiple seasons

In [ ]:
years = list(range(2022, 2018, -1))
all_matches = []
years
Out[ ]:
[2022, 2021, 2020, 2019]
In [ ]:
import time
for year in years:
    data = requests.get(standing_url)
    soup = BeautifulSoup(data.text)
    standing_table = soup.select('table.stats_table')[0]

    links = [l.get("href") for l in standing_table.find_all('a')]
    links = [l for l in links if '/squads/' in l]
    team_urls = [f"https://fbref.com{l}" for l in links]

    previous_season = soup.select("a.prev")[0].get("href")
    standings_url = f"https://fbref.com{previous_season}"

# scraping through each individual team logs 
    for team_url in team_urls:
        #geting individual team names 
        team_name = team1_url.split("/")[-1].replace("-Stats", "").replace("-", " ")
        #getting individual team match stats
        data = requests.get(team_url)
        matches = pd.read_html(data.text, match="Scores & Fixtures")[0]
        #getting shooting stats
        soup = BeautifulSoup(data.text)
        links = [l.get("href") for l in soup.find_all('a')]
        links = [l for l in links if l and 'all_comps/shooting/' in l]
        data = requests.get(f"https://fbref.com{links[0]}")
        shooting = pd.read_html(data.text, match="Shooting")[0]
        shooting.columns = shooting.columns.droplevel()
        ##############################################################################################
        # when mergering the two tables some of the shooting data in some teams is not available so ##
        # to overcome that, we have to use try-except statements                                    ##
        ##############################################################################################
        try:
            epl_team_data = matches.merge(shooting[["Date", "Sh", "SoT", "Dist", "FK", "PK", "PKatt"]], on="Date")
        except ValueError:
            continue
        
        epl_team_data = epl_team_data[epl_team_data["Comp"]=="Premier League"]
        epl_team_data["season"] = year
        epl_team_data["Team"] = team_name

        all_matches.append(epl_team_data)
        time.sleep(1)
In [ ]:
len(all_matches)
Out[ ]:
80
In [ ]:
epl_matches = pd.concat(all_matches)
In [ ]:
epl_matches
Out[ ]:
Date Time Comp Round Day Venue Result GF GA Opponent ... Match Report Notes Sh SoT Dist FK PK PKatt season Team
1 2018-08-12 16:00 Premier League Matchweek 1 Sun Away W 2 0 Arsenal ... Match Report NaN 17.0 8.0 18.2 1.0 0 0 2022 Manchester City
2 2018-08-19 13:30 Premier League Matchweek 2 Sun Home W 6 1 Huddersfield ... Match Report NaN 32.0 14.0 18.0 1.0 0 0 2022 Manchester City
3 2018-08-25 12:30 Premier League Matchweek 3 Sat Away D 1 1 Wolves ... Match Report NaN 18.0 6.0 18.6 1.0 0 0 2022 Manchester City
4 2018-09-01 17:30 Premier League Matchweek 4 Sat Home W 2 1 Newcastle Utd ... Match Report NaN 24.0 8.0 17.5 3.0 0 0 2022 Manchester City
5 2018-09-15 15:00 Premier League Matchweek 5 Sat Home W 3 0 Fulham ... Match Report NaN 28.0 9.0 16.6 1.0 0 0 2022 Manchester City
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
35 2019-04-13 12:30 Premier League Matchweek 34 Sat Away L 0 4 Tottenham ... Match Report NaN 7.0 1.0 18.9 1.0 0 0 2019 Manchester City
36 2019-04-20 15:00 Premier League Matchweek 35 Sat Home L 1 2 Watford ... Match Report NaN 13.0 3.0 18.1 1.0 0 0 2019 Manchester City
37 2019-04-26 20:00 Premier League Matchweek 36 Fri Away L 0 5 Liverpool ... Match Report NaN 5.0 1.0 21.6 0.0 0 0 2019 Manchester City
38 2019-05-05 14:00 Premier League Matchweek 37 Sun Home D 1 1 Manchester Utd ... Match Report NaN 7.0 3.0 19.0 1.0 0 0 2019 Manchester City
39 2019-05-12 15:00 Premier League Matchweek 38 Sun Away D 1 1 Southampton ... Match Report NaN 10.0 3.0 22.2 0.0 0 0 2019 Manchester City

3040 rows × 27 columns

In [ ]:
epl_matches.columns = [c.lower() for c in epl_matches.columns]
In [ ]:
epl_matches.to_csv("epl_matches(season from 2019-2022)")
In [ ]: