CoderCastrov logo
CoderCastrov
Машинное обучение

Парсинг табличных данных с использованием Python

Парсинг табличных данных с использованием Python
просмотров
6 мин чтение
#Машинное обучение
Table Of Content

Как спарсить данные об игроках NBA с использованием BeautifulSoup, Selenium и Pandas в Python.

Одна из проблем при выполнении проекта машинного обучения - это сборка набора данных.

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

Я уже долгое время пишу о техниках машинного обучения, используя статистику игроков NBA в качестве исходных данных. Одним из самых часто задаваемых мне вопросов является то, могу ли я поделиться данными, потому что люди хотели бы поиграть с ними.

В Азии есть старая поговорка:

Дай человеку рыбу, и ты накормишь его на день; научи человека ловить рыбу, и ты накормишь его на всю жизнь.

Итак, в этой статье я хотел бы поделиться с вами, как спарсить табличные данные с веб-страниц с помощью Python.

Помимо стандартных шагов, я также расскажу о практических проблемах, с которыми я столкнулся, и решениях, чтобы их решить.



Подготовка инструментов

pip install beautifulsoup4 
pip install selenium
pip install requests
pip install pandas

Выше приведены коды для установки четырех необходимых пакетов Python, которые в большинстве случаев достаточны.

После успешной установки этих пакетов просто импортируйте их в среду Python.

import requests
from bs4 import BeautifulSoup
from selenium import webdriver
import pandas as pd

Если вы используете Google Chrome в качестве браузера по умолчанию, убедитесь, что chromedriver является исполняемым файлом в вашем PATH. В противном случае вы можете столкнуться с такой же проблемой, как и я, с сообщением об ошибке ниже.

Сообщение: 'chromedriver' исполняемый файл должен находиться в PATH

Чтобы решить эту проблему, просто загрузите chromedriver с https://sites.google.com/a/chromium.org/chromedriver/home и поместите его в исполняемый путь или добавьте его текущее расположение в переменную PATH системы.

Чтобы добавить его расположение в PATH, откройте файл ~/.bash_profile, набрав

vi ~/.bash_profile

Затем добавьте следующую строку в конец файла,

# add chromedriverexport PATH="/Users/yourdirectorytoCHROMEDIRVER:$PATH"

Чтобы проверить, является ли chromedriver исполняемым, просто введите chromedriver в терминале, и вы увидите сообщение от пакета,

На данный момент у нас есть все необходимые инструменты.



Инспектирование веб-страницы

Сначала нам нужно найти целевую страницу. В качестве примера этого руководства я буду использовать страницу статистики игрока НБА на сайте basketball-reference. Вот URL моей целевой страницы:

URL = [https://www.basketball-reference.com/players/i/irvinky01.html](https://www.basketball-reference.com/players/i/irvinky01.html)

Чтобы собрать данные с определенной веб-страницы, нам нужно знать ее структуру через вид разработчика. Щелкните правой кнопкой мыши на странице и щелкните левой кнопкой мыши кнопку «Инспектировать», как показано ниже.

Затем вы увидите скрипт веб-страницы справа, как показано ниже.

Показанная выше информация едва читаема для человека, но после тщательной проверки вы можете обнаружить некоторые шаблоны.

Например, таблицы на странице всегда начинаются с <table …> и заканчиваются </table> (выделено синим на графике выше). И эти таблицы именно то, что я хочу получить со страницы.

Скрапинг таблиц

Теперь мы собираемся скрэпить эти таблицы со страницы, используя Beautifulsoup. Стандартный способ получить все таблицы со страницы выглядит так:

page = requests.get(URL)
soup = BeautifulSoup(page.content, 'html.parser')
tables = soup.find_all("table")

где requests.get(URL) получает информацию со страницы, а BeautifulSoup(page.content, 'html.parser') парсит эту информацию.

Затем мы можем применить функцию find_all к распарсенной информации в soup. soup.find_all("table") собирает все блоки информации, которые начинаются с <table> и заканчиваются </table>.

Для каждой таблицы в переменной tables, обычно заголовки таблицы начинаются с <th>, а все ячейки таблицы строк начинаются с <td>. Таким образом, таблицу можно извлечь и преобразовать в pandas data frame в следующем коде.

table = tables[0]
tab_data = [[cell.text for cell in row.find_all(["th","td"])]
                        for row in table.find_all("tr")]
df = pd.DataFrame(tab_data)

Сгенерированный data frame выглядит следующим образом:

Чтобы переместить первую строку в заголовки, просто введите

df.columns = df.iloc[0,:]
df.drop(index=0,inplace=True)

Чтобы получить все таблицы со страницы таким же образом, как первую таблицу (tables[0]), я создал словарь и использовал атрибут 'id' каждой таблицы внутри цикла for.

tabs_dic = {}
    
for table in tables:
    tab_name = table['id']
        
    tab_data = [[cell.text for cell in row.find_all(["th","td"])]
                        for row in table.find_all("tr")]
    df = pd.DataFrame(tab_data)
    df.columns = df.iloc[0,:]
    df.drop(index=0,inplace=True)
        
    #df = df.loc[df.Season != ""]
    tabs_dic[tab_name] = df

Я смог извлечь идентификатор таблицы с помощью table['id'], потому что 'id' является атрибутом таблицы, который является 'per_game', как показано ниже:

Таким образом, у меня должны быть все таблицы в формате pandas data frame, размещенные в большом словаре tabs_dic.

Однако у меня возникла проблема...



Проблема с парсингом нескольких таблиц

Когда я впервые попытался изучить номера таблиц на странице игрока, я столкнулся с проблемой, что я парсил только ОДНУ таблицу!

Я использовал find_all("table") как показано в предыдущем коде, как я мог пропустить все остальные таблицы, кроме первой?!

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

Затем я использовал Selenium, чтобы решить эту проблему.

driver = webdriver.Chrome()
driver.get(URL)
soup = BeautifulSoup(driver.page_source,'html')
driver.quit()
tables = soup.find_all('table')

Вышеуказанный код решил проблему и успешно получил 75 таблиц.

Я снова был сбит с толку, потому что 75 казалось мне слишком много. Я проверял веб-страницу снова и снова и обнаружил, что хотя некоторые блоки начинаются с <table>, они содержат только одно или два значения и не являются нужными мне таблицами.

Поэтому я дополнительно изменил код, чтобы выбрать несколько классов таблиц на странице на основе атрибута class таблиц.

tables = soup.find_all('table',{"class":["row_summable sortable stats_table now_sortable","suppress_all sortable stats_table now_sortable","sortable stats_table now_sortable","suppress_glossary sortable stats_table now_sortable"]})

где информация о class передавалась в функцию в формате словаря.

В итоге я получил всего 22 таблицы.

Функция парсинга статистики игроков NBA с basketball-reference

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

def получить_все_вкладки_страницы_игрока(URL = '[https://www.basketball-reference.com/players/i/irvinky01.html'](https://www.basketball-reference.com/players/i/irvinky01.html')):
    driver = webdriver.Chrome()
    driver.get(URL)
    soup = BeautifulSoup(driver.page_source,'html')
    driver.quit()
    tables = soup.find_all('table',{"class":["row_summable sortable stats_table now_sortable","suppress_all sortable stats_table now_sortable","sortable stats_table now_sortable","suppress_glossary sortable stats_table now_sortable"]})
    tabs_dic = {}
    
    for table in tables:
        tab_name = table['id']
        
        tab_data = [[cell.text for cell in row.find_all(["th","td"])] for row in table.find_all("tr")]
        df = pd.DataFrame(tab_data)
        df.columns = df.iloc[0,:]
        df.drop(index=0,inplace=True)
        
        tabs_dic[tab_name] = df
    
    return tabs_dic

Парсинг веб-страницы - это мощный навык, особенно для тех, кто интересуется применением методов машинного обучения в некоторых интересных областях.

Например, навык парсинга является основой для всех следующих постов, которые я написал о машинном обучении и баскетболе.

Кто является MVP НБА в этом сезоне?

Исследование для определения самого ценного игрока НБА в этом сезоне с использованием машинного обучения.

towardsdatascience.com

Представление важности признаков в классификаторе "Случайный лес"

Как построить классификатор "Случайный лес", извлечь важность признаков и красиво их представить.

towardsdatascience.com

Проект прогнозирования игр на основе статистики Леброна с использованием трех моделей машинного обучения

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

towardsdatascience.com

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

Руководство по визуализации данных в R-пакете "ggplot2" для статистики игроков НБА

6-минутный обзор инструмента визуализации данных R, "ggplot2", примененного к данным НБА.

towardsdatascience.com

Вот и все! Ура! Теперь вы должны знать, как парсить табличные данные с помощью Python.


Ссылки: