Укажите, какую таблицу чистить на странице - PullRequest
0 голосов
/ 28 мая 2018

Страница, о которой идет речь: http://stats.nba.com/player/2544/shots-dash/?Season=2017-18&SeasonType=Playoffs&LastNGames=6&sort=FGM&dir=1

, и я пытаюсь почистить 5-ю таблицу.

Сначала я попытался получить заголовки столбцов, выполнив:

from urllib.request import urlopen
from bs4 import BeautifulSoup
import pandas as pd

url = 'http://stats.nba.com/player/2544/shots-dash/?Season=2017-18&SeasonType=Playoffs&LastNGames=6'
html = urlopen(url)
soup = BeautifulSoup(html, "html.parser")

column_headers = [th.getText() for th in soup.findAll('tr')[1].findAll('th')]

data_rows = soup.findAll('tr')[1:]

, но затем я получил ошибку IndexError: list index out of range, и мой data_rows оказался пустым.

Что, в свою очередь, заставило меня понять, что все теги для каждой таблицы на этой странице идентичны, и поэтому я не совсем уверен, как указать точную таблицу, которую я хочу ...

1 Ответ

0 голосов
/ 28 мая 2018

Сайт, который вы дали, построен на Angular ведьме JavaScript framework.Таким образом, загрузка HTML-кода до того, как Angular заполнит его, даст вам только череп веб-сайта, который является базовым HTML-кодом без необходимых данных.

Итак, чтобы ответить на ваш вопрос, вы должны знать,логика, лежащая в основе вашей цели, ведьма - приложение, созданное с Angular.Немного изучив, вы обнаружите, что Angular - это, в основном, потребитель API.

Отправляя запросы, которые сделал ваш браузер, вы найдете конечную точку API, которую Angular использует для заполнения таблицссылка, которую вы дали.

Вот пример того, как вы можете проанализировать конечную точку API и получить нужные данные:

import json
from urllib.request import urlopen, Request 


# API endpoint where Angular gets the data and it'll fill the tables with
url = 'http://stats.nba.com/stats/playerdashptshots?DateFrom=&DateTo=&GameSegment=&LastNGames=6&LeagueID=00&Location=&Month=0&OpponentTeamID=0&Outcome=&PerMode=PerGame&Period=0&PlayerID=2544&Season=2017-18&SeasonSegment=&SeasonType=Playoffs&TeamID=0&VsConference=&VsDivision='

# The server behind the website checks the headers
# So you need to add to your request at least 
# a valid Cookie and a user agent
headers = {
    'Cookie': 'ak_bmsc=98B4FD680504382D1BE219CE963DE520ADDE6D86FF260000CD220B5B87B91E5E~ploZrwUVSrpu3HO/7DratALkZS/cK+SOZ9zMvNJNvJ6u/dYH50zISBdr3kK2S6ifBH/zXh9Z8oBFFeq1so2FGYfl29Zob9z065l/0caXBy5CNT3gOCn3OojgRPe7j1LLDThGl7eYQju8bl+1dO24vr5r9U+YngrmtlXpUPX+IT6Z7YoJPXP9YHmx1FMCyr7FOKmTyJL7js91F1pGVKGEOE/plhHEB4P7sq3B0uRzWWWcc=; s_cc=true; s_fid=5CA44E6CD67BA096-0F573C9E17BE0B09; s_sq=%5B%5BB%5D%5D; bm_sv=682C33C8686155B97E1B1692275AF96F~HweJkyeagLOu7iHDyl4xgtUAYOpT0NW49tH2OZpG93uH9+RTvrfGREItatT/72/WL3cY/k2VeYr/tDO1feFxAvO+Xe8fzIw2JOH4A/0lRXqp709dcJb53l9AytLTOgoHaQ4UG7rjPBPyMSoFFeJ3tg==',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
}
# Building the request
request = Request(url, headers=headers)
with urlopen(request, timeout=3) as f:
    data = f.read().decode('utf8')

# Convert the JSON to a valid Python dict
data_json = json.loads(data)
# Get the data of the 5th table
desired_table = data_json['resultSets'][5]
# Get the headers of the 5th table
data_headers = desired_table.get('headers')

# Print them out ...
# PS: You need to find how to pretty print them
# Like what the website do
# For example: Convert some floats to percentage etc..
for elm in desired_table.get('rowSet'):
    for head, val in zip(data_headers, elm):
        print('{0} : {1}'.format(head, val))
    print('#'*20)

output (первая строка 5-й таблицы):

PLAYER_ID : 2544
PLAYER_NAME_LAST_FIRST : James, LeBron
SORT_ORDER : 1
GP : 6
G : 1
CLOSE_DEF_DIST_RANGE : 0-2 Feet - Very Tight
FGA_FREQUENCY : 0.007
FGM : 0.0
FGA : 0.17
FG_PCT : 0.0
EFG_PCT : 0.0
FG2A_FREQUENCY : 0.007
FG2M : 0.0
FG2A : 0.17
FG2_PCT : 0.0
FG3A_FREQUENCY : 0.0
FG3M : 0.0
FG3A : 0.0
FG3_PCT : None
####################
...

И чтобы понять, как вы можете красиво распечатать эти значения, веб-сайт использует шаблон с тегами [посетите эту ссылку ].

Интересная часть:

  <tbody>
    <tr data-ng-repeat="(i, row) in page" index="{{ ::i }}">
      <td class="player">
        <span ng-if="title==='Overall'">{{ ::row.SHOT_TYPE }}</span>
        <span ng-if="title==='GeneralShooting'">{{ ::row.SHOT_TYPE }}</span>
        <span ng-if="title==='ShotClockShooting'">{{ ::row.SHOT_CLOCK_RANGE }}</span>
        <span ng-if="title==='ClosestDefenderShooting'">{{ ::row.CLOSE_DEF_DIST_RANGE }}</span>
        <span ng-if="title==='ClosestDefender10ftPlusShooting'">{{ ::row.CLOSE_DEF_DIST_RANGE }}</span>
        <span ng-if="title==='DribbleShooting'">{{ ::row.DRIBBLE_RANGE }}</span>
        <span ng-if="title==='TouchTimeShooting'">{{ ::row.TOUCH_TIME_RANGE }}</span>
      </td>
      <td>{{ ::row.GP }}</td>
      <td>{{ ::row.G }}</td>
      <td>{{ ::row.FGA_FREQUENCY | percent }}%</td>
      <td>{{ ::row.FGM | permode:params.PerMode }}</td>
      <td>{{ ::row.FGA | permode:params.PerMode }}</td>
      <td>{{ ::row.FG_PCT | percent }}</td>
      <td>{{ ::row.EFG_PCT | percent }}</td>
      <td>{{ ::row.FG2A_FREQUENCY | percent }}%</td>
      <td>{{ ::row.FG2M | permode:params.PerMode }}</td>
      <td>{{ ::row.FG2A | permode:params.PerMode }}</td>
      <td>{{ ::row.FG2_PCT | percent }}</td>
      <td>{{ ::row.FG3A_FREQUENCY | percent }}%</td>
      <td>{{ ::row.FG3M | permode:params.PerMode }}</td>
      <td>{{ ::row.FG3A | permode:params.PerMode }}</td>
      <td>{{ ::row.FG3_PCT | percent }}</td>
    </tr>
  </tbody> 

Наконец, будьте хороши с веб-сайтом и не засыпайте его спамом.

Редактировать: Я нашел эту схему API предоставленный самим сайтом на Github, который объясняет данные в конечных точках API.Вы можете прочитать его, чтобы узнать, как работать с выходами JSON.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...