2
votes

Python Beautiful Soup ne trouve pas de table spécifique

Je rencontre des problèmes avec le grattage de basketball-reference.com. J'essaye d'accéder à la table "Team Per Game Stats" mais je n'arrive pas à cibler le bon div / table. J'essaye de capturer la table et de l'amener dans un dataframe en utilisant des pandas.

J'ai essayé d'utiliser soup.find et soup.find_all pour trouver toutes les tables mais quand je recherche les résultats, je ne vois pas l'ID de la table que je recherche. Voir ci-dessous.

x = soup.find("table", id="team-stats-per_game")

import csv, time, sys, math
import numpy as np
import pandas as pd
import requests 
from bs4 import BeautifulSoup
import urllib.request


#NBA season
year = 2019

# URL page we will scraping
url = "https://www.basketball-reference.com/leagues/NBA_2019.html#all_team-stats-base".format(year)

# Basketball reference URL
html = urlopen(url)
soup = BeautifulSoup(html,'lxml')

x = soup.find("table", id="team-stats-per_game")
print(x)


Result:

None

Je m'attends à ce que la sortie répertorie les éléments de la table, en particulier les balises tr et th à cibler et à intégrer dans un pandas df.


2 commentaires

Je soupçonne que la table est chargée via AJAX et n'est donc pas disponible via une belle soupe. L'enregistrement du HTML retourné par urlopen montre que la table avec cet ID est bien présente mais est incluse dans un commentaire HTML. Je vous suggère d'essayer Selenium .


duplication possible stackoverflow.com/questions/42310021/… et stackoverflow.com/questions/46305314/...


3 Réponses :


3
votes

Comme Jarett l'a mentionné ci-dessus, BeautifulSoup ne peut pas analyser votre balise. Dans ce cas, c'est parce qu'il est commenté dans la source. Bien que cette approche soit certes amateur, elle fonctionne pour vos données.

table_src = html.text.split('<div class="overthrow table_container" 
id="div_team-stats-per_game">')[1].split('</table>')[0] + '</table>'

table = BeautifulSoup(table_src, 'lxml')


0 commentaires

1
votes

Comme d'autres réponses l'ont mentionné, cela est essentiellement dû au fait que le contenu de la page est chargé à l'aide de JavaScript et que l'obtention du code source à l'aide d'urlopener ou d'une requête ne chargera pas cette partie dynamique.

Donc, ici, j'ai un moyen de contourner en fait, vous pouvez utiliser le sélénium pour laisser le contenu dynamique se charger, puis obtenir le code source à partir de là et rechercher la table. Voici le code qui donne réellement le résultat attendu. Mais vous devrez configurer le pilote Web sélénium

from lxml import html
from bs4 import  BeautifulSoup
from time import sleep
from selenium import webdriver


def parse(url):
    response = webdriver.Firefox()
    response.get(url)
    sleep(3)
    sourceCode=response.page_source
    return  sourceCode


year =2019
soup = BeautifulSoup(parse("https://www.basketball-reference.com/leagues/NBA_2019.html#all_team-stats-base".format(year)),'lxml')
x = soup.find("table", id="team-stats-per_game")
print(x)


0 commentaires

1
votes

Les tableaux sont rendus après, vous devez donc utiliser Selenium pour le rendre ou comme mentionné ci-dessus. Mais ce n'est pas nécessaire car la plupart des tableaux se trouvent dans les commentaires. Vous pouvez utiliser BeautifulSoup pour extraire les commentaires, puis rechercher dans ceux-ci les balises de la table.

print (tables[3])
      Rk                     Team   G     MP    FG  ...  STL  BLK   TOV    PF   PTS
0    1.0         Milwaukee Bucks*  82  19780  3555  ...  615  486  1137  1608  9686
1    2.0   Golden State Warriors*  82  19805  3612  ...  625  525  1169  1757  9650
2    3.0     New Orleans Pelicans  82  19755  3581  ...  610  441  1215  1732  9466
3    4.0      Philadelphia 76ers*  82  19805  3407  ...  606  432  1223  1745  9445
4    5.0    Los Angeles Clippers*  82  19830  3384  ...  561  385  1193  1913  9442
5    6.0  Portland Trail Blazers*  82  19855  3470  ...  546  413  1135  1669  9402
6    7.0   Oklahoma City Thunder*  82  19855  3497  ...  766  425  1145  1839  9387
7    8.0         Toronto Raptors*  82  19880  3460  ...  680  437  1150  1724  9384
8    9.0         Sacramento Kings  82  19730  3541  ...  679  363  1095  1751  9363
9   10.0       Washington Wizards  82  19930  3456  ...  683  379  1154  1701  9350
10  11.0         Houston Rockets*  82  19830  3218  ...  700  405  1094  1803  9341
11  12.0            Atlanta Hawks  82  19855  3392  ...  675  419  1397  1932  9294
12  13.0   Minnesota Timberwolves  82  19830  3413  ...  683  411  1074  1664  9223
13  14.0          Boston Celtics*  82  19780  3451  ...  706  435  1052  1670  9216
14  15.0           Brooklyn Nets*  82  19980  3301  ...  539  339  1236  1763  9204
15  16.0       Los Angeles Lakers  82  19780  3491  ...  618  440  1284  1701  9165
16  17.0               Utah Jazz*  82  19755  3314  ...  663  483  1240  1728  9161
17  18.0       San Antonio Spurs*  82  19805  3468  ...  501  386   992  1487  9156
18  19.0        Charlotte Hornets  82  19830  3297  ...  591  405  1001  1550  9081
19  20.0          Denver Nuggets*  82  19730  3439  ...  634  363  1102  1644  9075
20  21.0         Dallas Mavericks  82  19780  3182  ...  533  351  1167  1650  8927
21  22.0          Indiana Pacers*  82  19705  3390  ...  713  404  1122  1594  8857
22  23.0             Phoenix Suns  82  19880  3289  ...  735  418  1279  1932  8815
23  24.0           Orlando Magic*  82  19780  3316  ...  543  445  1082  1526  8800
24  25.0         Detroit Pistons*  82  19855  3185  ...  569  331  1135  1811  8778
25  26.0               Miami Heat  82  19730  3251  ...  627  448  1208  1712  8668
26  27.0            Chicago Bulls  82  19905  3266  ...  603  351  1159  1663  8605
27  28.0          New York Knicks  82  19780  3134  ...  557  422  1151  1713  8575
28  29.0      Cleveland Cavaliers  82  19755  3189  ...  534  195  1106  1642  8567
29  30.0        Memphis Grizzlies  82  19880  3113  ...  684  448  1147  1801  8490
30   NaN           League Average  82  19815  3369  ...  626  406  1155  1714  9119

[31 rows x 25 columns]

Cela vous renverra une liste de dataframes, alors sortez simplement la table que vous voulez où qu'elle soit est repéré par sa position d'index:

Sortie:

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

#NBA season
year = 2019

url = 'https://www.basketball-reference.com/leagues/NBA_2019.html#all_team-stats-base'.format(year)
response = requests.get(url)

soup = BeautifulSoup(response.text, 'html.parser')

comments = soup.find_all(string=lambda text: isinstance(text, Comment))

tables = []
for each in comments:
    if 'table' in each:
        try:
            tables.append(pd.read_html(each)[0])
        except:
            continue


0 commentaires