kevinskyba / kickbase-api-doc

A documentation of the kickbase API for scientific reasons only!
MIT License
22 stars 4 forks source link

Kickbase-Api: Spieler der aktuellen Saison #5

Open AlexKipke opened 1 week ago

AlexKipke commented 1 week ago

Hallo,

zurzeit baue ich ein Hilfstool für Kickbase und wollte fragen, ob es über die aktuelle v4 API eine Möglichkeit gibt, sich alle Spieler dieser Saison anzeigen zu lassen. Ich habe mir alle Endpunkte angeschaut, aber nichts Direktes gefunden, da man anscheinend immer die playerID als Parameter benötigt.

Eine Idee, die ich mir vorstellen könnte, wäre, den folgenden Endpunkt zu nutzen:

https://api.kickbase.com/v4/leagues/{{leagueId}}/players/{{playerId}}/performance

indem man eine Schleife laufen lässt und die playerID schrittweise erhöht. So könnte man alle Spieler erfassen, die Einträge zur Saison 24/25 haben.

Dabei sehe ich allerdings folgende Probleme:

Vielleicht hat jemand eine effizientere Methode, die ich übersehen habe.

casudo commented 1 week ago

Hallo @AlexKipke. 😀

Aus meiner Sicht wäre es am einfachsten, wenn du dir folgenden Endpunkt anschaust: https://api.kickbase.com/v4/competitions/1/teams/<team_id>/teamprofile

Dort bekommst du für jedes Team alle Spieler aufgelistet. Dementsprechend werden nur Spieler aufgelistet, die diese Saison mit im Kader sind.

Ich habe mir in meinem Program eine loop gebaut, die sich alle Team Spieler in den Teams mit der ID 2 bis 100 abholt.

def get_team_overview(token: str) -> dict:
    """### Get all team names + ID and their players.

    Args:
        token (str): The user's kkstrauth token.

    Returns:
        dict: A dictionary containing all team ids + names and players.
    """
    logging.info("Getting team overview...")

    url = "https://api.kickbase.com/v4/competitions/1/teams/{team_id}/teamprofile"
    headers = {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Cookie": f"kkstrauth={token};",
    }

    all_teams = []

    ### Loop through team IDs from 2 to 100
    for team_id in range(2, 101):
        if team_id in [33, 38]:  ### Skip team IDs 33 and 38 cuz they are leading to "500 Internal Server Error"
            continue

        try:
            response = requests.get(url.format(team_id=team_id), headers=headers)
            response.raise_for_status()  # Raise an HTTPError for bad responses (4xx and 5xx)
            if response.content:  # Check if the response is not empty
                json_response = response.json()
            else:
                logging.warning(f"Empty response for team id {team_id}")
                continue
        except requests.exceptions.RequestException as e:
            logging.warning(f"Failed to get team id {team_id}: {e}")
            continue
        except json.JSONDecodeError as e:
            logging.warning(f"Failed to decode JSON for team id {team_id}: {e}")
            continue

        ### Check if team has players
        if json_response["it"]:
            ### Get team id, name, and players
            team_info = {
                "teamId": json_response["tid"],
                "teamName": json_response["tn"],
                "players": json_response["it"]
            }
            all_teams.append(team_info)

    logging.info("Got all teams.")

    ### Save to file
    miscellaneous.write_json_to_file(all_teams, "STATIC_teams.json")

    return all_teams

Laut meinen eigenen Erfahrung kannst du schon sehr häufig und oft hintereinander in kurzen Abständen Anfragen an die API schicken, ohne irgendwie geblockt zu werden.

Ich hoffe das hilft dir. 👍🏽

simonsagstetter commented 1 week ago

Hi @AlexKipke,

ich knüpfe da mal an das bereits gute beispiel von @casudo mit einem javascript snippet an, wie ich es machen würde. Du kannst auch verschiedene Endpoints kombinieren, um an das Ziel zu kommen.

  1. Tabelle und Team Ids abrufen https://api.kickbase.com/v4/competitions/:competitionId/table

    const {it: tableArray} = await fetch("https://api.kickbase.com/v4/competitions/1/table")
    const teamIds = tableArray.map(team=>team.tid)
  2. Alle Spieler der Teams abrufen https://api.kickbase.com/v4/competitions/:competitionId/teams/:teamId/teamprofile

const promises = teamIds.map(async(id)=>{
 const {it: teamPlayers} = await fetch(`https://api.kickbase.com/v4/competitions/1/teams/${id}/teamprofile`)
 return teamPlayers;
})

const results = await Promise.all(promises);
const allPlayers = results.flat(); // Das sind alle Spieler der Saison

Wenn du etwas Abstand zwischen den Abfragen lässt, sollte das kein Problem sein. Wahrscheinlich wird der Großteil der Anfragen auf Kickbase in der App gecached, weswegen übermäßige Abfragen natürlich auffällig sein können. Ich würde dir empfehlen, dir zum Testen die API Responses abzuspeichern und dir eine Mock Response zu bauen.

Viel Erfolg!

AlexKipke commented 1 week ago

@simonsagstetter @casudo

Perfekt, danke euch für die schnelle Hilfe !

AlexKipke commented 1 week ago

Hallo @casudo ,

mir ist bei der Nutzung des Endpunktes https://api.kickbase.com/v4/leagues/:leagueId/teams/:teamId/teamprofile/

ein Fehler aufgefallen.

Man bekommt dort in "it" alle spieler aufgelistet.

Anschließend kann man dann für jeden Spieler sehen, ob dieser gerade im Besitzt eines Managers ist oder nicht. Das sieht man anhand der "onm" property.

Nun zum eigentlichen Fehler:

Es gibt Spieler, bei welchen die "onm" property nicht angegeben ist, die aber in der Kickbase app definitiv einen Besitzer haben

Das konnte ich stichprobenartig bei mehreren Spielern feststellen. Kannst du mal bei dir schauen, ob du den Fehler nachvollziehen kannst ?

casudo commented 1 week ago

Hi Alex, ich bin jetzt ebenfalls stichprobenartig mehrere Teams durchgegangen und musste feststellen, dass ich bei keinem einzigen Team/Spieler den "onm" Parameter auffinden konnte.

AlexKipke commented 6 days ago

Ich habe den falschen Endpunkt rein kopiert. Bei dem genannten gibt es den "onm" Parameter nicht

Ich meinte diesen hier

https://api.kickbase.com/v4/leagues/:leagueId/teams/:teamId/teamprofile/

habe es auch im Kommentar angepasst

simonsagstetter commented 6 days ago

Hi Alex,

ich kann definitiv bestätigen das die onm object property innerhalb desit arrays nur dann definiert ist, wenn der Spieler im Kader eine Manager der Liga ist. Ist sie nicht definiert, dann ist der Spieler im Besitz von Kickbase und wird früher oder später auf den aktiven Transfermarkt rotiert.

Das lässt sich andersrum über den endpoint /v4/competitions/:competitionId/players/:playerId bestätigen.

Ich konnte aber leider noch nicht reproduzieren, dass die onm property undefiniert ist, der Spieler aber im Kader eines Managers ist. Hast du das beides per API Aufruf überprüft oder hast du es in der Kickbase App nachgeprüft? Kann gerne sein dass manche Ergebnisse in der App gecached sind. Das wäre meine einzige Idee für diese Anomalie... :(

Vielleicht kannst du einen Response Body mit den zugehörigen Abfragen in den Issue posten?

AlexKipke commented 6 days ago

Hier ist der API Aufruf mit dem Beispiel Waldemar Anton vom BVB. Hier müsste die onm property definiert sein. image

Ist definitiv im Besitz eines Managers, wie man am Manager Profilbild sieht. image

Dieses Verhalten ist mir noch bei zwei weiteren Spieler aufgefallen. Diese Spieler sind auch sind auch schon seid mehreren Monaten im Besitzt, sodass ich Caching evtl ausschließen. Ich kann es mir nicht erklären.

Im /v4/competitions/:competitionId/players/:playerId wird mir wiederum der Besitzer für Anton angezeigt. Also im Zweifel muss ich über diesen Punkt prüfen. Finde es nur komisch, dass es bei euch funktioniert und bei mir nicht :(

simonsagstetter commented 6 days ago

Kann es sein dass du bei https://api.kickbase.com/v4/leagues/:leagueId/teams/:teamId/teamprofile/ das Team Profil innerhalb einer anderen Liga abrufst? Ein Tippfehler in der :leagueId?

Denn /v4/competitions/:competitionId/players/:playerId erhälst du die Informationen, wer den Spieler besitzt, jewels für jede Liga, in der du spielst. Das kannst du auch in der App sehen in Competitions>Tabelle>Dortmund>Anton und dann nach unten scrollen.