Очистить каждый стол из выпадающего меню Python - PullRequest
1 голос
/ 11 апреля 2020

Я собираюсь просмотреть статистику Отдела 3 по баскетболу в колледже со следующей страницы статистики NCAA:

https://stats.ncaa.org/rankings/change_sport_year_div

Чтобы попасть на страницу, на которой я нахожусь, После нажатия на ссылку выберите Спорт = Баскетбол для мужчин, Год = 2019-2020 и Div = III

. При нажатии на ссылку, над таблицей в верхнем левом углу появляется раскрывающийся список. Он помечен как «Дополнительная статистика». Для каждой статистики есть таблица, из которой вы можете получить файл Excel, но я хочу быть более эффективным. Я думал, что мог бы быть способ перебрать выпадающую панель с помощью BeautifulSoup (или, возможно, даже pd.read_ html), чтобы получить фрейм данных для каждой перечисленной статистики. Есть ли способ сделать это? Прохождение каждой статистики вручную, загрузка файла Excel и чтение файла Excel в pandas было бы затруднительно. Спасибо.

enter image description here

Ответы [ 2 ]

1 голос
/ 12 апреля 2020

Вот мое предложение: использовать комбинацию requests, beautifulsoup и отличный html анализатор таблиц из Скотт Рим (я немного изменил функцию parse_html_table, чтобы удалить \n и удалите пробелы).

Во-первых, при проверке исходного кода страницы вы можете увидеть, что она имеет вид: "https://stats.ncaa.org/rankings/national_ranking?academic_year=2020.0&division=3.0&ranking_period=110.0&sport_code=MBB&stat_seq=145.0", например, для стат 145 ie «Оценка нарушения».

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

# <option value="625">3-pt Field Goal Attempts</option>
# <option value="474">Assist Turnover Ratio</option>
# <option value="216">Assists Per Game</option>
# ...

Для определенного c показателя, например, здесь для оценки нарушения можно использовать следующий код для извлечения таблицы как pandas DataFrame:

import pandas as pd
from bs4 import BeautifulSoup
import requests


el = "https://stats.ncaa.org/rankings/national_ranking?academic_year=2020.0&division=3.0&ranking_period=110.0&sport_code=MBB&stat_seq=145.0"
page = requests.get(el).content.decode('utf-8')
soup = BeautifulSoup(page, "html.parser")
ta = soup.find_all('table', {"id": "rankings_table"})

# Scott Rome function tweaked a bit
def parse_html_table(table):
    n_columns = 0
    n_rows = 0
    column_names = []

    # Find number of rows and columns
    # we also find the column titles if we can
    for row in table.find_all('tr'):

        # Determine the number of rows in the table
        td_tags = row.find_all('td')
        if len(td_tags) > 0:
            n_rows += 1
            if n_columns == 0:
                # Set the number of columns for our table
                n_columns = len(td_tags)

        # Handle column names if we find them
        th_tags = row.find_all('th')
        if len(th_tags) > 0 and len(column_names) == 0:
            for th in th_tags:
                column_names.append(th.get_text())

    # Safeguard on Column Titles
    if len(column_names) > 0 and len(column_names) != n_columns:
        raise Exception("Column titles do not match the number of columns")

    columns = column_names if len(column_names) > 0 else range(0, n_columns)
    df = pd.DataFrame(columns=columns,
                      index=range(0, n_rows))
    row_marker = 0
    for row in table.find_all('tr'):
        column_marker = 0
        columns = row.find_all('td')
        for column in columns:
            df.iat[row_marker, column_marker] = column.get_text()
            column_marker += 1
        if len(columns) > 0:
            row_marker += 1

    # remove \n
    for col in df:
        try:
            df[col] = df[col].str.replace("\n", "")
            df[col] = df[col].str.strip()
        except ValueError:
            pass
    # Convert to float if possible
    for col in df:
        try:
            df[col] = df[col].astype(float)
        except ValueError:
            pass

    return df


example = parse_html_table(ta[0])

Результат

 Rank                           Team    GM    W-L    PTS    PPG
0    1             Greenville (SLIAC)  27.0  14-13  3,580  132.6
1    2  Grinnell (Midwest Conference)  25.0  13-12  2,717  108.7
2    3             Pacific (OR) (NWC)  25.0   7-18  2,384   95.4
3    4                  Whitman (NWC)  28.0   20-8  2,646   94.5
4    5            Valley Forge (ACAA)  22.0  12-11  2,047   93.0
...

Теперь вам нужно применить это ко всем значениям статистики, указанным выше.

Вы можете создать функцию из приведенного выше кода и применить ее в a для l oop к URL-адресу "https://stats.ncaa.org/rankings/national_ranking?academic_year=2020.0&division=3.0&ranking_period=110.0&sport_code=MBB&stat_seq={}".format(stat), где stat находится в списке всех возможных значений.

Надеюсь, это поможет.

0 голосов
/ 12 апреля 2020

Возможно, более краткий способ сделать это:

import requests as rq
from bs4 import BeautifulSoup as bs
import pandas as pd

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0)     Gecko/20100101 Firefox/76.0"}
params = {"sport_code": "MBB", "stat_seq": "518", "academic_year": "2020.0",  "division":"3.0", "ranking_period":"110.0"}
url = "https://stats.ncaa.org/rankings/national_ranking"

resp = rq.post(url, headers=headers, params=params)
soup = bs(resp.content)

colnames = [th.text.strip() for th in soup.find_all("thead")[0].find_all("th")]
data = [[td.text.strip() for td in tr.find_all('td')] for tr in soup.find_all('tbody')[0].find_all("tr")]

df = pd.DataFrame(data, columns=colnames)
df.astype({"GM": 'int32'}).dtypes # convert column in type u want

Вы должны посмотреть на запросы XHR [в Mozilla: F12 -> Сеть -> XHR].

Когда вы выберите элемент в раскрывающемся списке, после чего отправляется запрос по следующему URL: https://stats.ncaa.org/rankings/national_ranking.

Некоторые параметры необходимы для отправки этого запроса на публикацию, одним из них является "stat_seq". Значение соответствует «значению» раскрывающихся опций.

Инспектор выдаст вам список соответствия «значение» -StatName:

<option value="625" selected="selected">3-pt Field Goal Attempts</option>
<option value="474">Assist Turnover Ratio</option>
<option value="216">Assists Per Game</option>
<option value="214">Blocked Shots Per Game</option>
<option value="859">Defensive Rebounds per Game</option>
<option value="642">Fewest Fouls</option>
...
...
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...