Как собрать данные игроков Fantasy Premier League (FPL) на Mac с использованием API, Python и Cron
Table Of Content
- С небольшим количеством работы вы можете настроить свой Mac для автоматического сбора данных FPL ежедневно
- Сделать GET-запрос для получения последних данных об игроках из FPL API
- Преобразовать данные JSON в объект Python
- Инициализировать массив для хранения ВСЕХ данных об игроках
- Это будет двумерный массив, где каждая строка - это отдельный игрок
- Преобразование двумерного массива в массив numpy
- Сгенерировать уникальное имя файла на основе даты
- Это будет двумерный массив, где каждая строка - это отдельный игрок
С небольшим количеством работы вы можете настроить свой Mac для автоматического сбора данных FPL ежедневно
В этой статье я предполагаю, что у читателя есть некоторый опыт работы с Python. Здесь нет ничего новаторского, так как мы полагаемся на библиотеки для выполнения основной работы.
Примечание: Полный код Python доступен внизу страницы в полном объеме.
Немного погуглив о скрапинге данных FPL, я смог найти ссылку на FPL API, предоставленную пользователем reddit u/eramit2010, здесь. Ссылка с нашими данными - первая, https://fantasy.premierleague.com/api/bootstrap-static/. Щелкните по ней, и вы получите представление о том, с чем мы работаем. Теперь перейдем к коду Python.
Прежде всего, мы хотим импортировать необходимые библиотеки.
import requests
import json
import numpy as np
import pandas as pd
import datetime
В этом случае мы импортируем requests и json, чтобы помочь нам получить данные, numpy и pandas, чтобы помочь с их обработкой, и datetime, чтобы позволить нам сохранять каждый файл CSV с уникальным именем на основе даты.
Затем нам нужно сделать запрос на получение данных (информации об игроках) из источника (fantasy.premierleague.com). Мы сделаем это, используя библиотеку request и функцию get().
# Сделать GET-запрос для получения последних данных об игроках из FPL API
link = "[https://fantasy.premierleague.com/api/bootstrap-static/](https://fantasy.premierleague.com/api/bootstrap-static/)"
response = requests.get(link)
К сожалению, эти данные находятся в формате JSON, поэтому нам нужно преобразовать их в объект Python с помощью функции loads() из библиотеки json.
# Преобразовать данные JSON в объект Python
data = json.loads(response.text)
Теперь, когда у нас есть данные в удобном формате, пришло время начать их обработку. В этом случае мы будем перебирать каждую запись игрока, собирать статистику текущего игрока и добавлять ее в общий список со статистикой для каждого игрока. Каждая строка будет представлять собой отдельного игрока, а каждый столбец - отдельную категорию статистики.
# Инициализировать массив для хранения ВСЕХ данных об игроках
# Это будет двумерный массив, где каждая строка - это отдельный игрок
all_players = []# Перебор каждого игрока в данных
for i in data["elements"]:
assists = i['assists']
bonus = i['bonus']
bps = i['bps']
chance_of_playing_next_round = i['chance_of_playing_next_round']
chance_of_playing_this_round = i['chance_of_playing_this_round']
clean_sheets = i['clean_sheets']
code = i['code']
cost_change_event = i['cost_change_event']
cost_change_event_fall = i['cost_change_event_fall']
cost_change_start = i['cost_change_start']
cost_change_start_fall = i['cost_change_start_fall']
creativity = i['creativity']
dreamteam_count = i['dreamteam_count']
element_type = i['element_type']
ep_next = i['ep_next']
ep_this = i['ep_this']
event_points = i['event_points']
first_name = i['first_name']
form = ['form']
goals_conceded = i['goals_conceded']
goals_scored = i['goals_scored']
ict_index = i['ict_index']
i_d = i['id']
in_dreamteam = i['in_dreamteam']
influence = i['influence']
minutes = i['minutes']
news = i['news']
news_added = i['news_added']
now_cost = i['now_cost']
own_goals = i['own_goals']
penalties_missed = i['penalties_missed']
penalties_saved = i['penalties_saved']
photo = i['photo']
points_per_game = i['points_per_game']
red_cards = i['red_cards']
saves = i['saves']
second_name = i['second_name']
selected_by_percent = i['selected_by_percent']
special = i['special']
squad_number = i['squad_number']
status = i['status']
team = i['team']
team_code = i['team_code']
threat = i['threat']
total_points = i['total_points']
transfers_in = i['transfers_in']
transfers_in_event = i['transfers_in_event']
transfers_out = i['transfers_out']
transfers_out_event = i['transfers_out_event']
value_form = i['value_form']
value_season = i['value_season']
web_name = i['web_name']
yellow_cards = i['yellow_cards'] # Создание одномерного массива статистики текущего игрока
individual_stats = [assists, bonus, bps,
chance_of_playing_next_round, chance_of_playing_this_round,
clean_sheets, code, cost_change_event,
cost_change_event_fall, cost_change_start,
cost_change_start_fall, creativity,
dreamteam_count, element_type, ep_next, ep_this,
event_points, first_name, form, goals_conceded,
goals_scored, ict_index, i_d, in_dreamteam, influence,
minutes, news, news_added, now_cost, own_goals,
penalties_missed, penalties_saved, photo,
points_per_game, red_cards, saves, second_name,
selected_by_percent, special, squad_number, status,
team, team_code, threat, total_points, transfers_in,
transfers_in_event, transfers_out, transfers_out_event,
value_form, value_season, web_name, yellow_cards] # Добавление массива игрока в двумерный массив всех игроков
all_players.append(individual_stats)
Затем мы преобразуем его в массив numpy, чтобы легче получить данные в виде таблицы pandas, а затем преобразуем этот массив numpy в таблицу pandas.
# Преобразование двумерного массива в массив numpy
all_players = np.array(all_players)# Преобразование массива numpy в таблицу pandas
dataset = pd.DataFrame({'assists': all_players[:, 0],
'bonus': all_players[:, 1],
'bps': all_players[:, 2],
'chance_of_playing_next_round': all_players[:, 3],
'chance_of_playing_this_round': all_players[:, 4],
'clean_sheets': all_players[:, 5],
'code': all_players[:, 6],
'cost_change_event': all_players[:, 7],
'cost_change_event_fall': all_players[:, 8],
'cost_change_start': all_players[:, 9],
'cost_change_start_fall': all_players[:, 10],
'creativity': all_players[:, 11],
'dreamteam_count': all_players[:, 12],
'element_type': all_players[:, 13],
'ep_next': all_players[:, 14],
'ep_this': all_players[:, 15],
'event_points': all_players[:, 16],
'first_name': all_players[:, 17],
'form': all_players[:, 18],
'goals_conceded': all_players[:, 19],
'goals_scored': all_players[:, 20],
'ict_index': all_players[:, 21],
'i_d': all_players[:, 22],
'in_dreamteam': all_players[:, 23],
'influence': all_players[:, 24],
'minutes': all_players[:, 25],
'news': all_players[:, 26],
'news_added': all_players[:, 27],
'now_cost': all_players[:, 28],
'own_goals': all_players[:, 29],
'penalties_missed': all_players[:, 30],
'penalties_saved': all_players[:, 31],
'photo': all_players[:, 32],
'points_per_game': all_players[:, 33],
'red_cards': all_players[:, 34],
'saves': all_players[:, 35],
'second_name': all_players[:, 36],
'selected_by_percent': all_players[:, 37],
'special': all_players[:, 38],
'squad_number': all_players[:, 39],
'status': all_players[:, 40],
'team': all_players[:, 41],
'team_code': all_players[:, 42],
'threat': all_players[:, 43],
'total_points': all_players[:, 44],
'transfers_in': all_players[:, 45],
'transfers_in_event': all_players[:, 46],
'transfers_out': all_players[:, 47],
'transfers_out_event': all_players[:, 48],
'value_form': all_players[:, 49],
'value_season': all_players[:, 50],
'web_name': all_players[:, 51],
'yellow_cards': all_players[:, 52]})
На этом этапе у нас есть данные в удобном формате и мы можем начать анализ, но мы сохраним это для другого скрипта. Чтобы сохранить данные, мы сгенерируем уникальное имя на основе даты, а затем воспользуемся функцией to_csv() из pandas, чтобы сохранить CSV в той же директории, где находится наш скрипт Python.
# Сгенерировать уникальное имя файла на основе даты
filename = str(datetime.datetime.today().date()) + '_fpl_players'# Сохранить таблицу данных в формате CSV
dataset.to_csv(index=False, path_or_buf=filename)
Соберите все вместе, и мы легко можем создать CSV-файл со всеми доступными нам данными. Теперь перейдем к ежедневной автоматизации.
Чтобы настроить его для ежедневного запуска, мы воспользуемся cron, планировщиком заданий на основе Unix, и создадим файл crontab (таблицу cron). Мы будем работать исключительно в терминале, поэтому откройте его и введите crontab -e
(опция -e
означает редактирование). Это откроет ваш файл crontab в vi (мощный, но без фанатизма текстовый редактор с некоторым крутым функционалом). Нажмите i
, чтобы войти в режим ввода, а затем введите следующее (я объясню):
0 21 * * * cd <путь к скрипту Python> && <путь к python>/python <путь к скрипту Python>/all_players_API_scraper.py
В файле crontab каждая строка представляет собой отдельное задание и состоит из шести параметров: минуты (0–59), часы (0–23), день месяца (1–31), месяц (1–12), день недели (0–6) и команда оболочки. Звездочка используется в качестве заполнителя, когда вы хотите, чтобы код выполнялся для каждого значения параметра (например, звездочка в третьей позиции означает каждый день месяца). В этом случае у меня есть две команды bash, связанные вместе (с помощью &&
), запланированные для выполнения каждый день в 21:00, но вы можете запланировать свое выполнение в любое удобное для вас время. Хотя это кажется избыточным, переход в директорию с помощью команды cd
необходим для установки переменной среды для Python.
Чтобы найти <путь к python>
, введите "which python" в терминале, а чтобы найти <путь к скрипту Python>
, введите 'pwd' в терминале в той же папке, где находится скрипт.
Примечание: Cron не будет работать, если ваш компьютер находится в спящем режиме.
И вот мы и закончили! Скрипт Python, который собирает и форматирует наши данные, выполняется автоматически каждый день.
Полный код Python:
import requests
import json
import numpy as np
import pandas as pd
import datetime# Сделать GET-запрос для получения последних данных об игроках из FPL API
link = "[https://fantasy.premierleague.com/api/bootstrap-static/](https://fantasy.premierleague.com/api/bootstrap-static/)"
response = requests.get(link)# Преобразовать данные JSON в объект Python
data = json.loads(response.text)# Инициализировать массив для хранения ВСЕХ данных об игроках
# Это будет двумерный массив, где каждая строка - это отдельный игрок
all_players = []# Перебор каждого игрока в данных
for i in data["elements"]:
assists = i['assists']
bonus = i['bonus']
bps = i['bps']
chance_of_playing_next_round = i['chance_of_playing_next_round']
chance_of_playing_this_round = i['chance_of_playing_this_round']
clean_sheets = i['clean_sheets']
code = i['code']
cost_change_event = i['cost_change_event']
cost_change_event_fall = i['cost_change_event_fall']
cost_change_start = i['cost_change_start']
cost_change_start_fall = i['cost_change_start_fall']
creativity = i['creativity']
dreamteam_count = i['dreamteam_count']
element_type = i['element_type']
ep_next = i['ep_next']
ep_this = i['ep_this']
event_points = i['event_points']
first_name = i['first_name']
form = ['form']
goals_conceded = i['goals_conceded']
goals_scored = i['goals_scored']
ict_index = i['ict_index']
i_d = i['id']
in_dreamteam = i['in_dreamteam']
influence = i['influence']
minutes = i['minutes']
news = i['news']
news_added = i['news_added']
now_cost = i['now_cost']
own_goals = i['own_goals']
penalties_missed = i['penalties_missed']
penalties_saved = i['penalties_saved']
photo = i['photo']
points_per_game = i['points_per_game']
red_cards = i['red_cards']
saves = i['saves']
second_name = i['second_name']
selected_by_percent = i['selected_by_percent']
special = i['special']
squad_number = i['squad_number']
status = i['status']
team = i['team']
team_code = i['team_code']
threat = i['threat']
total_points = i['total_points']
transfers_in = i['transfers_in']
transfers_in_event = i['transfers_in_event']
transfers_out = i['transfers_out']
transfers_out_event = i['transfers_out_event']
value_form = i['value_form']
value_season = i['value_season']
web_name = i['web_name']
yellow_cards = i['yellow_cards']# Создание одномерного массива статистики текущего игрока
individual_stats = [assists, bonus, bps,
chance_of_playing_next_round, chance_of_playing_this_round,
clean_sheets, code, cost_change_event,
cost_change_event_fall, cost_change_start,
cost_change_start_fall, creativity,
dreamteam_count, element_type, ep_next, ep_this,
event_points, first_name, form, goals_conceded,
goals_scored, ict_index, i_d, in_dreamteam, influence,
minutes, news, news_added, now_cost, own_goals,
penalties_missed, penalties_saved, photo,
points_per_game, red_cards, saves, second_name,
selected_by_percent, special, squad_number, status,
team, team_code, threat, total_points, transfers_in,
transfers_in_event, transfers_out, transfers_out_event,
value_form, value_season, web_name, yellow_cards]# Добавление массива игрока в двумерный массив всех игроков
all_players.append(individual_stats)# Преобразование двумерного массива в массив numpy
all_players = np.array(all_players)# Преобразование массива numpy в таблицу pandas
dataset = pd.DataFrame({'assists': all_players[:, 0],
'bonus': all_players[:, 1],
'bps': all_players[:, 2],
'chance_of_playing_next_round': all_players[:, 3],
'chance_of_playing_this_round': all_players[:, 4],
'clean_sheets': all_players[:, 5],
'code': all_players[:, 6],
'cost_change_event': all_players[:, 7],
'cost_change_event_fall': all_players[:, 8],
'cost_change_start': all_players[:, 9],
'cost_change_start_fall': all_players[:, 10],
'creativity': all_players[:, 11],
'dreamteam_count': all_players[:, 12],
'element_type': all_players[:, 13],
'ep_next': all_players[:, 14],
'ep_this': all_players[:, 15],
'event_points': all_players[:, 16],
'first_name': all_players[:, 17],
'form': all_players[:, 18],
'goals_conceded': all_players[:, 19],
'goals_scored': all_players[:, 20],
'ict_index': all_players[:, 21],
'i_d': all_players[:, 22],
'in_dreamteam': all_players[:, 23],
'influence': all_players[:, 24],
'minutes': all_players[:, 25],
'news': all_players[:, 26],
'news_added': all_players[:, 27],
'now_cost': all_players[:, 28],
'own_goals': all_players[:, 29],
'penalties_missed': all_players[:, 30],
'penalties_saved': all_players[:, 31],
'photo': all_players[:, 32],
'points_per_game': all_players[:, 33],
'red_cards': all_players[:, 34],
'saves': all_players[:, 35],
'second_name': all_players[:, 36],
'selected_by_percent': all_players[:, 37],
'special': all_players[:, 38],
'squad_number': all_players[:, 39],
'status': all_players[:, 40],
'team': all_players[:, 41],
'team_code': all_players[:, 42],
'threat': all_players[:, 43],
'total_points': all_players[:, 44],
'transfers_in': all_players[:, 45],
'transfers_in_event': all_players[:, 46],
'transfers_out': all_players[:, 47],
'transfers_out_event': all_players[:, 48],
'value_form': all_players[:, 49],
'value_season': all_players[:, 50],
'web_name': all_players[:, 51],
'yellow_cards': all_players[:, 52]})# Сгенерировать уникальное имя файла на основе даты
filename = str(datetime.datetime.today().date()) + '_fpl_players'# Сохранить таблицу данных в формате CSV
dataset.to_csv(index=False, path_or_buf=filename)