Часть 1: Сбор данных (веб-скрейпинг)

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

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

Рассматриваемые темы:
– Какие сайты разрешают парсинг из своего robots.txt файла
– Парсинг HTML-таблиц с помощью python.
– Расширенный парсинг: проверка того, как данные передаются на веб-сайт.
– Хранение данные.

Можете ли вы очистить этот сайт?

Чтобы проверить, разрешает ли сайт веб-скрапинг или нет, вам нужно проверить файл robots.txt для этого сайта. Чтобы найти это, перейдите на доменное имя веб-сайта и добавьте /robots.txt в конец.

Пример. Если сайт, который вы хотите очистить, называется https://google.com, то файл robots.txt находится по адресу https://google.com/robots.txt.

На этой странице вы найдете поле «Disallow» и поле «user-agent».
- Если вы видите «Disallow:», вы можете свободно очищать весь сайт.
– Если вы видите «Запретить: /», то вы не можете очистить этот сайт (на законных основаниях).
– Если вы видите «Запретить: /user/», вы не можете очистить эту конкретную страницу.
– Если вы видите «
User-agent: *», это означает каждого посетителя.

Если вы видите следующее

User-agent: *
Disallow:

Это означает, что каждый посетитель имеет полный доступ к очистке сайта.
Примечание. Убедитесь, что если у вас есть какие-либо страницы с параметром «Запретить: /{page}», вы не выполняете очистку этих конкретных страниц.

Очистка HTML-таблицы

Подавляющее большинство веб-страниц с таблицами данных html можно легко очистить с помощью pandas read_html.

import pandas as pddfs = pd.read_html(“https://en.wikipedia.org/wiki/Super_Bowl_LIV") 
print(dfs[0])
nfl_df = dfs[0]

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

Расширенный анализ данных

Иногда данные, которые вы видите на веб-странице, заполняются с помощью ajax, а не в HTML. В этом случае вам нужно выяснить, куда передаются данные.

Находим данные:

  • Откройте инструменты разработчика в веб-браузере. (F12 — обычное сочетание клавиш)
  • На вкладках вверху выберите Сеть

  • Держите это окно открытым, затем перейдите на веб-страницу с данными, которые вы хотите очистить. Пример сайта: https://fantasydata.com/nfl/fantasy-football-leaders. Чтобы увидеть параметры запроса и то, как проходят различные фильтры данных, обязательно выберите разные годы или должности.
  • Перейдя на веб-страницу, вы можете найти фактический сетевой запрос, содержащий данные, которые вы хотите получить. Простой способ сделать это — выполнить текстовый поиск в запросах. Для этого щелкните строку запроса, нажмите ctrl + F. Рядом с вашим текущим представлением появится отдельный графический интерфейс. Найдите очень уникальное имя, которое обычно не используется случайно.

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

В python мы собираемся настроить программу, имитирующую действия браузера. Мы собираемся создать объект заголовков, строку URL-адреса и объект данных формы, который мы будем использовать для передачи параметров данных. Они должны имитировать запрос, который мы только что записали.

import requests
import pandas as pdurl = 'https://fantasydata.com/NFL_FantasyStats/FantasyStats_Read'
headers = {
        'accept': 'application/json, text/javascript, */*; q=0.01',
        'accept-encoding': 'gzip, deflate'
    }
formdata = {
            'sort': 'FantasyPoints-desc',
            'pageSize': '300',
            'filters.position': '2',
            'filters.season': '2020',
            'filters.seasontype': '1',
            'filters.scope': '2',
            'filters.subscope': '1',
            'filters.startweek': '5',
            'filters.endweek': '5',
            'filters.aggregatescope': '1',
            'filters.range': '3',
            }
sesh = requests.session()
resp = sesh.get(url, headers = headers, data = formdata)#Mimic Web Browser Request To Gather Data
data = r.json() #Grab Data In JSON format
df = pd.json_normalize(data) #Transform Json to dataframe

Это загрузит данные, которые вы видите в разделе ответа инструмента разработчика. Этот конкретный запрос собирает фантазийные данные QB за 5-ю неделю сезона 2020 года. Теперь вы можете записывать эти данные итеративно.

The above mimics one request, you should set up some for loops that go through different positions, seasons, weeks to gather all data.outpos = 'QB'
yr = 2020
wk = 5#This will write out the formatted dataframe to the Data/QB/ Folder. #File: Data/QB/QB_2020_5.csv
df.to_csv('Data/'+str(outpos).upper()+'/'+str(outpos)+'_'+str(yr)+'_'+str(wk)+'.csv')

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

qbfiles =  [f for f in os.listdir('Data/QB/') if os.path.isfile(os.path.join('Data/QB/', f))] #Grab All File Names
qb_dfs = [] #Create List Of Dataframes
for q in qbfiles: 
    qb_dfs.append(pd.read_csv('Data/QB/'+q, index_col = 0))
qb_df = pd.concat(qb_dfs).drop_duplicates().reset_index(drop=True)
qb_df.to_csv('Data/qb_stats_all.csv')

Теперь у вас есть один файл для каждой позиции. На основе столбцов данных вы сможете добавить все позиции в один файл. Пример будет выглядеть так:

all_players = pd.concat([qb_df, rb_df, wr_df, te_df])
all_players.to_csv('Data/player_stats_all.csv')

Мы на шаг ближе к работе с этими данными и построению прогнозной модели dfs.

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

Для данных нажмите здесь.

НАПИСАНО

Тейлор Монтичелли

Data Scientist @ Day & Zimmermann