website scraping soccer analytics with bs5

Viewed 42

I have adopted this code from a medium post, currently it works for the first id but is not looping through the ranges:

import requests
from bs4 import BeautifulSoup
import json
import pandas as pd


understat_ids = range(16376, 16755+1)
match_data = []


for id in understat_ids:
    base_urls = f'https://understat.com/match/{id}'
#Use requests to get the webpage and BeautifulSoup to parse the page
    res = requests.get(base_urls)
    soup = BeautifulSoup(res.content, 'lxml')
    scripts = soup.find_all('script')
#get only the shotsData
    strings = scripts[1].string

# strip unnecessary symbols and get only JSON data
    ind_start = strings.index("('")+2
    ind_end = strings.index("')")
    json_data = strings[ind_start:ind_end]
    json_data = json_data.encode('utf8').decode('unicode_escape')

#convert string to json format
    data = json.loads(json_data)

x = []
y = []
xG = []
result = []
team = []
minute = []
data_away = data['a']
data_home = data['h']
date = []
player = []
situation = []
shotType = []
matchId = []

for index in range(len(data_home)):
    for key in data_home[index]:
        if key == 'X':
            x.append(data_home[index][key])
        if key == 'Y':
            y.append(data_home[index][key])
        if key == 'h_team':
            team.append(data_home[index][key])
        if key == 'xG':
            xG.append(data_home[index][key])
        if key == 'minute':
            minute.append(data_home[index][key])
        if key == 'result':
            result.append(data_home[index][key])
        if key == 'situation':
            situation.append(data_home[index][key])
        if key == 'date':
            date.append(data_home[index][key])
        if key == 'player':
            player.append(data_home[index][key])
        if key == 'shotType':
            shotType.append(data_home[index][key])
        if key == 'match_id':
            matchId.append(data_home[index][key])


for index in range(len(data_away)):
    for key in data_away[index]:
        if key == 'X':
            x.append(data_away[index][key])
        if key == 'Y':
            y.append(data_away[index][key])
        if key == 'a_team':
            team.append(data_away[index][key])
        if key == 'xG':
            xG.append(data_away[index][key])
        if key == 'minute':
            minute.append(data_away[index][key])
        if key == 'result':
            result.append(data_away[index][key])
        if key == 'situation':
            situation.append(data_away[index][key])
        if key == 'date':
            date.append(data_away[index][key])
        if key == 'player':
           player.append(data_away[index][key])
        if key == 'shotType':
            shotType.append(data_away[index][key])
        if key == 'match_id':
            matchId.append(data_away[index][key])




col_names = ['x','y','xG','minute','result','situation','date','player','shotType','team','match_id']
df = pd.DataFrame([x,y,xG,minute,result,situation,date,player,shotType,team,matchId],index=col_names)
df = df.T

The above code works for one match the first ID specified in range, how can I edit this code to loop through each match id appending them on to a pandas dataframe?

It seems like the code needs a small edit to be able to do this.

1 Answers

As mentioned @MattDMo you have to check and adjust your indentation properly to ensure that either everything is processed within the loop.

Removing all these if-statements and lists, that are not necessary would improve readability of your code - Use a single line with list comprehension to create a list of dicts that you convert to a dataframe:

...
data = json.loads(json_data)
match_data.extend([d for k in data.keys() for d in data[k]])
    
pd.DataFrame(match_data)

Example

For demonstration I decreased the number of iterations, feel free to adjust it to your needs

import requests,json
from bs4 import BeautifulSoup
import pandas as pd

understat_ids = range(16376, 16400+1)
match_data = []

for id in understat_ids:
    base_urls = f'https://understat.com/match/{id}'
#Use requests to get the webpage and BeautifulSoup to parse the page
    res = requests.get(base_urls)
    soup = BeautifulSoup(res.content, 'lxml')
    scripts = soup.find_all('script')
#get only the shotsData
    strings = scripts[1].string

# strip unnecessary symbols and get only JSON data
    ind_start = strings.index("('")+2
    ind_end = strings.index("')")
    json_data = strings[ind_start:ind_end]
    json_data = json_data.encode('utf8').decode('unicode_escape')

#convert string to json format
    data = json.loads(json_data)
#iterate JSON and extend match_data with a list of dicts
    match_data.extend([d for k in data.keys() for d in data[k]])
    
pd.DataFrame(match_data)

Output

id minute result X Y xG player h_a player_id situation season shotType match_id h_team a_team h_goals a_goals date player_assisted lastAction
0 425564 10 MissedShots 0.913 0.539 0.053464 Frank Onyeka h 9681 OpenPlay 2021 Head 16376 Brentford Arsenal 2 0 2021-08-13 19:00:00 Aerial
1 425565 11 ShotOnPost 0.908 0.315 0.118297 Bryan Mbeumo h 6552 OpenPlay 2021 RightFoot 16376 Brentford Arsenal 2 0 2021-08-13 19:00:00 Ivan Toney Throughball
2 425567 21 Goal 0.874 0.698 0.0521447 Sergi Canos h 1078 OpenPlay 2021 RightFoot 16376 Brentford Arsenal 2 0 2021-08-13 19:00:00 Ethan Pinnock BallRecovery
3 425568 27 MissedShots 0.812 0.478 0.0657062 Sergi Canos h 1078 OpenPlay 2021 RightFoot 16376 Brentford Arsenal 2 0 2021-08-13 19:00:00 Frank Onyeka Pass
4 425569 29 MissedShots 0.892 0.357 0.0806906 Bryan Mbeumo h 6552 OpenPlay 2021 RightFoot 16376 Brentford Arsenal 2 0 2021-08-13 19:00:00 Kristoffer Ajer Chipped
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
650 428704 77 SavedShot 0.868 0.596 0.122391 Abdoulaye Doucouré a 1726 OpenPlay 2021 RightFoot 16400 Brighton Everton 0 2 2021-08-28 14:00:00 Demarai Gray Pass
651 428708 83 BlockedShot 0.913 0.688 0.0734056 Alex Iwobi a 500 OpenPlay 2021 RightFoot 16400 Brighton Everton 0 2 2021-08-28 14:00:00 Richarlison Pass
652 428709 83 SavedShot 0.778 0.753 0.0136589 André Gomes a 2383 FromCorner 2021 RightFoot 16400 Brighton Everton 0 2 2021-08-28 14:00:00 None
653 428711 90 BlockedShot 0.939 0.723 0.0615859 André Gomes a 2383 OpenPlay 2021 LeftFoot 16400 Brighton Everton 0 2 2021-08-28 14:00:00 Alex Iwobi Pass
654 428712 93 BlockedShot 0.704 0.703 0.015702 Lucas Digne a 1823 OpenPlay 2021 LeftFoot 16400 Brighton Everton 0 2 2021-08-28 14:00:00 Allan Pass
Related