How to scrape table off a website in dataframe format?

Question:

I tried scraping a table of the NBA site but got the error no tables found.

import requests
from bs4 import BeautifulSoup
import pandas as pd


url = 'https://www.nba.com/game/0022101100/play-by-play?latest=0'
html = requests.get(url).content
df_list = pd.read_html(html)


How do I go about getting the play-by-play table?

Asked By: TroyMcClure8998

||

Answers:

Data is loaded dynamically via API as json format.So you can extract them using json() and pandas as follows:

import requests
import pandas as pd
api_url = 'https://cdn.cookielaw.org/vendorlist/iab2Data.json'
headers= {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
    }

req=requests.get(api_url,headers=headers).json()

df = pd.DataFrame(req)
print(df)

Output:

 gvlSpecificationVersion  tcfPolicyVersion  ... vendorListVersion           lastUpdated
1                           2                 2  ...               159  2022-09-01T16:05:33Z
2                           2                 2  ...               159  2022-09-01T16:05:33Z
3                           2                 2  ...               159  2022-09-01T16:05:33Z
4                           2                 2  ...               159  2022-09-01T16:05:33Z
5                           2                 2  ...               159  2022-09-01T16:05:33Z
...                       ...               ...  ...               ...                   ...
1146                        2                 2  ...               159  2022-09-01T16:05:33Z
1147                        2                 2  ...               159  2022-09-01T16:05:33Z
1148                        2                 2  ...               159  2022-09-01T16:05:33Z
1149                        2                 2  ...               159  2022-09-01T16:05:33Z
1150                        2                 2  ...               159  2022-09-01T16:05:33Z

[907 rows x 10 columns]
Answered By: F.Hoque

As stated, that data is dynamically rendered. You could a) use Selenium to simulate opeing the browser, allowing the page to render, THEN use pandas to parse the table tags. or b) use the nba api and get the data in json format.

import requests
import pandas as pd

gameId = '0022101100'
url = f'https://cdn.nba.com/static/json/liveData/playbyplay/playbyplay_{gameId}.json'
jsonData = requests.get(url).json()
df = pd.json_normalize(jsonData,
                       record_path=['game', 'actions'])

Here is Option 2:

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


gameId = '0021900709'
url = f'https://www.nba.com/game/{gameId}/play-by-play'
headers = {
    'referer': 'https://www.nba.com/',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')

jsonStr = soup.find('script', {'id':'__NEXT_DATA__'}).text
jsonData = json.loads(jsonStr)['props']['pageProps']['playByPlay']
df = pd.json_normalize(jsonData,
                       record_path=['actions'])

Output: first 10 rows of 548

print(df.head(10).to_markdown())
|    |   actionNumber | clock       | timeActual             |   period | periodType   | actionType   | subType   | qualifiers           |   personId |        x |        y |   possession |   scoreHome |   scoreAway | edited               |   orderNumber |   xLegacy |   yLegacy |   isFieldGoal | side   | description                                            | personIdsFilter           |        teamId | teamTricode   | descriptor   | jumpBallRecoveredName   |   jumpBallRecoverdPersonId | playerName   | playerNameI    | jumpBallWonPlayerName   |   jumpBallWonPersonId | jumpBallLostPlayerName   |   jumpBallLostPersonId |   shotDistance | shotResult   |   pointsTotal | assistPlayerNameInitial   |   assistPersonId |   assistTotal |   officialId |   foulPersonalTotal |   foulTechnicalTotal | foulDrawnPlayerName   |   foulDrawnPersonId |   shotActionNumber |   reboundTotal |   reboundDefensiveTotal |   reboundOffensiveTotal |   turnoverTotal |   stealPlayerName |   stealPersonId |   blockPlayerName |   blockPersonId |   value |
|---:|---------------:|:------------|:-----------------------|---------:|:-------------|:-------------|:----------|:---------------------|-----------:|---------:|---------:|-------------:|------------:|------------:|:---------------------|--------------:|----------:|----------:|--------------:|:-------|:-------------------------------------------------------|:--------------------------|--------------:|:--------------|:-------------|:------------------------|---------------------------:|:-------------|:---------------|:------------------------|----------------------:|:-------------------------|-----------------------:|---------------:|:-------------|--------------:|:--------------------------|-----------------:|--------------:|-------------:|--------------------:|---------------------:|:----------------------|--------------------:|-------------------:|---------------:|------------------------:|------------------------:|----------------:|------------------:|----------------:|------------------:|----------------:|--------:|
|  0 |              2 | PT12M00.00S | 2022-03-25T23:10:44.0Z |        1 | REGULAR      | period       | start     | []                   |          0 | nan      | nan      |            0 |           0 |           0 | 2022-03-25T23:10:44Z |         20000 |       nan |       nan |             0 |        | Period Start                                           | []                        | nan           | nan           | nan          | nan                     |              nan           | nan          | nan            | nan                     |                   nan | nan                      |                    nan |         nan    | nan          |           nan | nan                       |    nan           |           nan |          nan |                 nan |                  nan | nan                   |                 nan |                nan |            nan |                     nan |                     nan |             nan |               nan |             nan |               nan |             nan |     nan |
|  1 |              4 | PT11M55.00S | 2022-03-25T23:10:47.2Z |        1 | REGULAR      | jumpball     | recovered | []                   |    1626220 | nan      | nan      |   1610612762 |           0 |           0 | 2022-03-25T23:10:47Z |         40000 |       nan |       nan |             0 |        | Jump Ball R. Gobert vs. M. Plumlee: Tip to R. O'Neale  | [1626220, 203497, 203486] |   1.61061e+09 | UTA           | startperiod  | R. O'Neale              |                1.62622e+06 | O'Neale      | R. O'Neale     | Gobert                  |                203497 | Plumlee                  |                 203486 |         nan    | nan          |           nan | nan                       |    nan           |           nan |          nan |                 nan |                  nan | nan                   |                 nan |                nan |            nan |                     nan |                     nan |             nan |               nan |             nan |               nan |             nan |     nan |
|  2 |              7 | PT11M36.00S | 2022-03-25T23:11:06.3Z |        1 | REGULAR      | 2pt          | DUNK      | ['pointsinthepaint'] |     203497 |  92.8548 |  47.0588 |   1610612762 |           0 |           2 | 2022-03-25T23:11:12Z |         70000 |       -15 |        15 |             1 | right  | R. Gobert DUNK (2 PTS) (D. Mitchell 1 AST)             | [203497, 1628378]         |   1.61061e+09 | UTA           | nan          | nan                     |              nan           | Gobert       | R. Gobert      | nan                     |                   nan | nan                      |                    nan |           2.08 | Made         |             2 | D. Mitchell               |      1.62838e+06 |             1 |          nan |                 nan |                  nan | nan                   |                 nan |                nan |            nan |                     nan |                     nan |             nan |               nan |             nan |               nan |             nan |     nan |
|  3 |              9 | PT11M21.00S | 2022-03-25T23:11:25.8Z |        1 | REGULAR      | foul         | personal  | ['2freethrow']       |     203497 | nan      | nan      |   1610612766 |           0 |           2 | 2022-03-25T23:11:38Z |         90000 |       nan |       nan |             0 |        | R. Gobert shooting personal FOUL (1 PF) (Plumlee 2 FT) | [203497, 203486]          |   1.61061e+09 | UTA           | shooting     | nan                     |              nan           | Gobert       | R. Gobert      | nan                     |                   nan | nan                      |                    nan |         nan    | nan          |           nan | nan                       |    nan           |           nan |       200832 |                   1 |                    0 | Plumlee               |              203486 |                nan |            nan |                     nan |                     nan |             nan |               nan |             nan |               nan |             nan |     nan |
|  4 |             11 | PT11M21.00S | 2022-03-25T23:11:50.7Z |        1 | REGULAR      | freethrow    | 1 of 2    | []                   |     203486 | nan      | nan      |   1610612766 |           0 |           2 | 2022-03-25T23:11:50Z |        110000 |       nan |       nan |             0 |        | MISS M. Plumlee Free Throw 1 of 2                      | [203486]                  |   1.61061e+09 | CHA           | nan          | nan                     |              nan           | Plumlee      | M. Plumlee     | nan                     |                   nan | nan                      |                    nan |         nan    | Missed       |           nan | nan                       |    nan           |           nan |          nan |                 nan |                  nan | nan                   |                 nan |                nan |            nan |                     nan |                     nan |             nan |               nan |             nan |               nan |             nan |     nan |
|  5 |             12 | PT11M21.00S | 2022-03-25T23:11:50.7Z |        1 | REGULAR      | rebound      | offensive | ['deadball', 'team'] |          0 | nan      | nan      |   1610612766 |           0 |           2 | 2022-03-25T23:11:50Z |        120000 |       nan |       nan |             0 |        | TEAM offensive REBOUND                                 | []                        |   1.61061e+09 | CHA           | nan          | nan                     |              nan           | nan          | nan            | nan                     |                   nan | nan                      |                    nan |         nan    | nan          |           nan | nan                       |    nan           |           nan |          nan |                 nan |                  nan | nan                   |                 nan |                 11 |            nan |                     nan |                     nan |             nan |               nan |             nan |               nan |             nan |     nan |
|  6 |             13 | PT11M21.00S | 2022-03-25T23:12:06.4Z |        1 | REGULAR      | freethrow    | 2 of 2    | []                   |     203486 | nan      | nan      |   1610612766 |           1 |           2 | 2022-03-25T23:12:06Z |        130000 |       nan |       nan |             0 |        | M. Plumlee Free Throw 2 of 2 (1 PTS)                   | [203486]                  |   1.61061e+09 | CHA           | nan          | nan                     |              nan           | Plumlee      | M. Plumlee     | nan                     |                   nan | nan                      |                    nan |         nan    | Made         |             1 | nan                       |    nan           |           nan |          nan |                 nan |                  nan | nan                   |                 nan |                nan |            nan |                     nan |                     nan |             nan |               nan |             nan |               nan |             nan |     nan |
|  7 |             14 | PT11M06.00S | 2022-03-25T23:12:22.2Z |        1 | REGULAR      | 3pt          | Jump Shot | []                   |    1626220 |  69.7273 |  75.2451 |   1610612762 |           1 |           2 | 2022-03-25T23:12:29Z |        140000 |       126 |       232 |             1 | right  | MISS R. O'Neale 26' 3PT                                | [1626220]                 |   1.61061e+09 | UTA           | nan          | nan                     |              nan           | O'Neale      | R. O'Neale     | nan                     |                   nan | nan                      |                    nan |          26.42 | Missed       |           nan | nan                       |    nan           |           nan |          nan |                 nan |                  nan | nan                   |                 nan |                nan |            nan |                     nan |                     nan |             nan |               nan |             nan |               nan |             nan |     nan |
|  8 |             15 | PT11M02.00S | 2022-03-25T23:12:26.2Z |        1 | REGULAR      | rebound      | offensive | []                   |    1627823 | nan      | nan      |   1610612762 |           1 |           2 | 2022-03-25T23:12:29Z |        150000 |       nan |       nan |             0 |        | J. Hernangomez REBOUND (Off:1 Def:0)                   | [1627823]                 |   1.61061e+09 | UTA           | nan          | nan                     |              nan           | Hernangomez  | J. Hernangomez | nan                     |                   nan | nan                      |                    nan |         nan    | nan          |           nan | nan                       |    nan           |           nan |          nan |                 nan |                  nan | nan                   |                 nan |                 14 |              1 |                       0 |                       1 |             nan |               nan |             nan |               nan |             nan |     nan |
|  9 |             16 | PT10M56.00S | 2022-03-25T23:12:33.1Z |        1 | REGULAR      | 3pt          | Jump Shot | ['2ndchance']        |    1628378 |  68.6761 |  70.098  |   1610612762 |           1 |           5 | 2022-03-25T23:12:38Z |        160000 |       100 |       242 |             1 | right  | D. Mitchell 26' 3PT  (3 PTS) (J. Hernangomez 1 AST)    | [1628378, 1627823]        |   1.61061e+09 | UTA           | nan          | nan                     |              nan           | Mitchell     | D. Mitchell    | nan                     |                   nan | nan                      |                    nan |          26.19 | Made         |             3 | J. Hernangomez            |      1.62782e+06 |             1 |          nan |                 nan |                  nan | nan                   |                 nan |                nan |            nan |                     nan |                     nan |             nan |               nan |             nan |               nan |             nan |     nan |
Answered By: chitown88