CoderCastrov logo
CoderCastrov
Питон

Как собрать данные игроков Fantasy Premier League (FPL) на Mac с использованием API, Python и Cron

Как собрать данные игроков Fantasy Premier League (FPL) на Mac с использованием API, Python и Cron
просмотров
8 мин чтение
#Питон

С небольшим количеством работы вы можете настроить свой 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)