Sofascore - zukünftige Spiele

Code-Stücke können hier veröffentlicht werden.
Antworten
FredN
User
Beiträge: 1
Registriert: Sonntag 16. Juni 2024, 20:26

Hallo Python Experten,
seit kurzer Zeit begeistere ich mich über die Möglichkeiten mit Python.
Allerdings bin ich erst am Anfang einer wohl eher langen Strecke.
Ich habe ein Python Script, welches die Spiele und Ergebnisse aus bestimmter Saison von der Webseite Sofascore feststellt und mit den Daten eine Excel Datei erzeugt.
Meine Frage;
In Sofascore sind auch die zukünftigen Paarungen der aktuellen Saison bestimmter Ligen abrufbar. Aber wie komme ich an diese Daten? Ich stelle in diesen Beitrag mein bisheriges Script rein,- die Korrektur dürfte wohl nicht so umfangreich sein. Kann ein Experte mal drauf schauen und mir bei der Modifizierung bitte helfen? Das Script ist auf die 1. Chinesische Liga ausgerichtet,- die noch am laufen ist. Ich möchte erreichen, das die noch "offenen Matches" in eine Excel geladen werden.
Script:

Code: Alles auswählen

import requests
import pandas as pd
import os
import time

def get_all_events(tournament_id, season_id):
    result = []
    i = 0
    hasNextPage = True
    while hasNextPage:
        url = f'https://www.sofascore.com/api/v1/unique-tournament/{tournament_id}/season/{season_id}/events/last/{i}'
        response = requests.get(url)
        data = response.json()
        hasNextPage = data.get('hasNextPage')
        result.extend(reversed(data.get('events', [])))
        i += 1

    return result

def get_match_incidents(event_id):
    url = f'https://www.sofascore.com/api/v1/event/{event_id}/incidents'
    response = requests.get(url)
    data = response.json()
    return data.get('incidents', [])

def main(tournament_id, season_id, output_file):
    data = []
    matches = get_all_events(tournament_id, season_id)
    for match in matches:
        incidents = get_match_incidents(match['id'])
        data.append([
            match['tournament']['name'],
            match['homeTeam']['name'],
            match['homeScore'].get('current', 'N/A'),
            match['awayTeam']['name'],
            match['awayScore'].get('current', 'N/A'),
            time.strftime('%x %X', time.localtime(int(match['startTimestamp']))),
            ', '.join(f"{i['time']}'" for i in incidents if i['incidentType'] == 'goal')
        ])

    headers = ['Tournament', 'Home Team', 'Home Score', 'Away Team', 'Away Score', 'Start Date', 'Goal Times']
    df = pd.DataFrame(data, columns=headers)
    df.to_excel(output_file, index=False)

if __name__ == '__main__':
    tournament_id = 649
    season_id = 58388
    output_file = "China_1_23-24.xlsx"
    main(tournament_id, season_id, output_file)
    
Der Abruf geht zwar recht langsam,- aber wohl sicher.

Gruss
Fred
Benutzeravatar
__blackjack__
User
Beiträge: 13339
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@FredN: Was ist denn das konkrete Problem dabei und wo findet man die API-Beschreibung?

Anmerkungen zum Quelltext: `os` wird importiert, aber nirgends verwendet.

Das Hauptprogramm sollte in einer Funktion verschwinden die `main()` heisst und die jetzige `main()` sollte einen sinnvolleren Namen bekommen.

`i` ist kein guter Name für etwas was keine ganze Zahl ist. Insbesondere wenn das dann auch noch die Laufvariable in einer Schleife oder „comprehension“ ist.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase). `hasNextPage` würde also `has_next_page` heissen.

Aber diesen Namen braucht man nicht. Python hat keine Syntax für eine nachprüfende Schleife. Statt das über ein Flag zu lösen, schreibt man besser eine ”Endlosschleife” die mit einem ``if`` und ``break`` verlassen wird.

HTTP-Antworten sollte man auf den Status prüfen (lassen).

Den Zeitstempel würde ich nicht ohne Not in eine Zeichenkette umwandeln. Pandas und Excel können Spalten mit Zeitstempeln. Ähnliches bei den „score“-Spalten — wenn da plötzlich auch Zeichenketten drin vorkommen können ist es für Pandas keine Zahlenspalte mehr. Üblicherweise verwendet man dafür `math.nan`.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import itertools
import math
from datetime import datetime as DateTime

import pandas as pd
import requests

API_URL = "https://www.sofascore.com/api/v1"


def get_all_events(tournament_id, season_id):
    events = []
    for i in itertools.count():
        response = requests.get(
            f"{API_URL}/unique-tournament/{tournament_id}/season/{season_id}"
            f"/events/last/{i}",
            timeout=None,
        )
        response.raise_for_status()
        data = response.json()
        events.extend(reversed(data.get("events", [])))
        if not data.get("hasNextPage"):
            break

    return events


def get_match_incidents(event_id):
    response = requests.get(
        f"{API_URL}/event/{event_id}/incidents", timeout=None
    )
    response.raise_for_status()
    return response.json().get("incidents", [])


def get_and_save_tournament(tournament_id, season_id, output_file):
    pd.DataFrame(
        [
            [
                match["tournament"]["name"],
                match["homeTeam"]["name"],
                match["homeScore"].get("current", math.nan),
                match["awayTeam"]["name"],
                match["awayScore"].get("current", math.nan),
                DateTime.fromtimestamp(int(match["startTimestamp"])),
                ", ".join(
                    str(incident["time"])
                    for incident in get_match_incidents(match["id"])
                    if incident["incidentType"] == "goal"
                ),
            ]
            for match in get_all_events(tournament_id, season_id)
        ],
        columns=[
            "Tournament",
            "Home Team",
            "Home Score",
            "Away Team",
            "Away Score",
            "Start Date",
            "Goal Times",
        ],
    ).to_excel(output_file, index=False)


def main():
    get_and_save_tournament(649, 58388, "China_1_23-24.xlsx")


if __name__ == "__main__":
    main()
“It is easier to optimize correct code than to correct optimized code.” — Bill Harlan
Antworten