J'ai essayé de gratter une table de ici depuis un certain temps mais j'ai été infructueuse. Le tableau que j'essaie de gratter s'intitule "Statistiques d'équipe par match". Je suis convaincu qu'une fois que je suis capable de gratter un élément de cette table, je peux parcourir les colonnes que je veux dans la liste et finir par obtenir une trame de données pandas.

Voici mon code jusqu'à présent:

from bs4 import BeautifulSoup
import requests

# url that we are scraping
r = requests.get('https://www.basketball-reference.com/leagues/NBA_2019.html')
# Lets look at what the request content looks like
print(r.content)

# use Beautifulsoup on content from request
c = r.content
soup = BeautifulSoup(c)
print(soup)

# using prettify() in Beautiful soup indents HTML like it should be in the web page
# This can make reading the HTML a little be easier
print(soup.prettify())

# get elements within the 'main-content' tag
team_per_game = soup.find(id="all_team-stats-per_game")
print(team_per_game)

Toute aide serait grandement appréciée.

2
Aaron England 16 mars 2019 à 17:55

2 réponses

Meilleure réponse

Cette page Web utilise une astuce pour essayer d'empêcher les moteurs de recherche et autres clients Web automatisés (y compris les scrapers) de trouver les données du tableau : les tableaux sont stockés dans des commentaires HTML :

<div id="all_team-stats-per_game" class="table_wrapper setup_commented commented">

<div class="section_heading">
  <span class="section_anchor" id="team-stats-per_game_link" data-label="Team Per Game Stats"></span><h2>Team Per Game Stats</h2>    <div class="section_heading_text">
      <ul> <li><small>* Playoff teams</small></li>
      </ul>
    </div>      
</div>
<div class="placeholder"></div>
<!--
   <div class="table_outer_container">
      <div class="overthrow table_container" id="div_team-stats-per_game">
  <table class="sortable stats_table" id="team-stats-per_game" data-cols-to-freeze=2><caption>Team Per Game Stats Table</caption>

...

</table>

      </div>
   </div>
-->
</div>

Je note que l'ouverture div a des classes setup_commented et commented. Le code Javascript inclus dans la page est ensuite exécuté par votre navigateur qui charge ensuite le texte de ces commentaires et remplace le div placeholder par le contenu en tant que nouveau code HTML à afficher par le navigateur.

Vous pouvez extraire le texte du commentaire ici :

from bs4 import BeautifulSoup, Comment

soup = BeautifulSoup(r.content, 'lxml')
placeholder = soup.select_one('#all_team-stats-per_game .placeholder')
comment = next(elem for elem in placeholder.next_siblings if isinstance(elem, Comment))
table_soup = BeautifulSoup(comment, 'lxml')

Puis continuez à analyser la table HTML.

Ce site spécifique a publié à la fois des conditions d'utilisation et des une page sur l'utilisation des données que vous devriez probablement lire si vous comptez utiliser leurs données. Plus précisément, leurs conditions indiquent, dans la section 6. Contenu du site :

Vous ne pouvez pas encadrer, capturer, récolter ou collecter une partie du site ou du contenu sans le consentement écrit préalable de SRL.

Le grattage des données relèverait de cette rubrique.

6
Martijn Pieters 16 mars 2019 à 18:23

Juste pour compléter la réponse de Martijn Pieters (et sans lxml)

from bs4 import BeautifulSoup, Comment
import requests

r = requests.get('https://www.basketball-reference.com/leagues/NBA_2019.html')
soup = BeautifulSoup(r.content, 'html.parser')
placeholder = soup.select_one('#all_team-stats-per_game .placeholder')
comment = next(elem for elem in placeholder.next_siblings if isinstance(elem, Comment))
table = BeautifulSoup(comment, 'html.parser')
rows = table.find_all('tr')
for row in rows:
    cells = row.find_all('td')
    if cells:
        print([cell.text for cell in cells])

Sortie partielle

[u'New Orleans Pelicans', u'71', u'240.0', u'43.6', u'91.7', u'.476', u'10.1', u'29.4', u'.344', u'33.5', u'62.4', u'.537', u'18.1', u'23.9', u'.760', u'11.0', u'36.0', u'47.0', u'27.0', u'7.5', u'5.5', u'14.5', u'21.4', u'115.5']
[u'Milwaukee Bucks*', u'69', u'241.1', u'43.3', u'90.8', u'.477', u'13.3', u'37.9', u'.351', u'30.0', u'52.9', u'.567', u'17.6', u'22.8', u'.773', u'9.3', u'40.1', u'49.4', u'26.0', u'7.4', u'6.0', u'14.0', u'19.8', u'117.6']
[u'Los Angeles Clippers', u'70', u'241.8', u'41.0', u'87.6', u'.469', u'9.8', u'25.2', u'.387', u'31.3', u'62.3', u'.502', u'22.8', u'28.8', u'.792', u'9.9', u'35.7', u'45.6', u'23.4', u'6.6', u'4.7', u'14.5', u'23.5', u'114.6']
1
balderman 16 mars 2019 à 15:29