football-docs 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,131 @@
1
+ # soccerdata Data Sources
2
+
3
+ ## FBref (sd.FBref)
4
+
5
+ Source: fbref.com, powered by StatsBomb/Opta data. HTTP-based, 7-second rate limit enforced. Supports "Big 5 European Leagues Combined" as a virtual league for efficient bulk scraping.
6
+
7
+ **Methods**:
8
+
9
+ | Method | Returns | Index | Notes |
10
+ |---|---|---|---|
11
+ | `read_leagues()` | League metadata | -- | |
12
+ | `read_seasons()` | Available seasons with URLs | -- | Includes round-robin vs elimination format |
13
+ | `read_schedule()` | Match schedule | `[league, season, game]` | Columns: week, date, time, home/away team, home/away xG, score, game_id |
14
+ | `read_team_season_stats(stat_type)` | Aggregated team stats | `[league, season, team]` | |
15
+ | `read_team_match_stats(stat_type)` | Per-match team logs | `[league, season, team, game]` | Optional `team` filter |
16
+ | `read_player_season_stats(stat_type)` | Aggregated player stats | `[league, season, team, player]` | |
17
+ | `read_player_match_stats(stat_type)` | Per-match player stats | `[league, season, game, team, player]` | Optional `match_id` filter |
18
+ | `read_lineup(match_id=None)` | Lineups | `[league, season, game]` | jersey_number, position, minutes_played, is_starter |
19
+ | `read_events(match_id=None)` | In-match events | `[league, season, game]` | Goals, cards, substitutions with timing |
20
+
21
+ **Team season stat types**: `standard`, `keeper`, `keeper_adv`, `shooting`, `passing`, `passing_types`, `goal_shot_creation`, `defense`, `possession`, `playing_time`, `misc`.
22
+
23
+ **Team match stat types**: `schedule`, `keeper`, `shooting`, `passing`, `passing_types`, `goal_shot_creation`, `defense`, `possession`, `misc`.
24
+
25
+ **Player match stat types**: `summary`, `keepers`, `passing`, `passing_types`, `defense`, `possession`, `misc`.
26
+
27
+ ## Understat (sd.Understat)
28
+
29
+ Source: understat.com. HTTP-based JSON API with initial cookie-setting request. Coverage: Big 5 European leagues only (EPL, La Liga, Serie A, Bundesliga, Ligue 1).
30
+
31
+ **Methods**:
32
+
33
+ | Method | Returns | Index | Notes |
34
+ |---|---|---|---|
35
+ | `read_leagues()` | League metadata | -- | |
36
+ | `read_seasons()` | Season metadata with URLs | -- | |
37
+ | `read_schedule()` | Match schedule | `[league, season, game]` | Includes home/away xG, goals, team codes |
38
+ | `read_team_match_stats()` | Per-match team stats | `[league, season, game]` | points, expected_points, xG, npxG, PPDA, deep_completions |
39
+ | `read_player_season_stats()` | Player season aggregates | `[league, season, team, player]` | goals, xG, npG, npxG, assists, xA, shots, key_passes, xGChain, xGBuildup |
40
+ | `read_player_match_stats()` | Per-match player stats | `[league, season, game, team, player]` | minutes, goals, shots, xG, xGChain, xGBuildup, assists, xA |
41
+ | `read_shot_events()` | Shot-level data | `[league, season, game, team, player]` | xG, location_x/y, body_part, situation, result |
42
+
43
+ **Shot event fields**: `body_part` (Right Foot / Left Foot / Other), `situation` (Open Play / From Corner / Set Piece / Direct Freekick), `result` (Goal / Blocked Shot / Saved Shot / Missed Shot / Shot On Post / Own Goal).
44
+
45
+ ## WhoScored (sd.WhoScored)
46
+
47
+ Source: whoscored.com (Opta event data). Selenium-based, requires Chrome/Chromium. Rate limit: 5s + 0-5s random delay. Constructor: `sd.WhoScored(leagues, seasons, path_to_browser=None, headless=False)`.
48
+
49
+ **Methods**:
50
+
51
+ | Method | Returns | Index | Notes |
52
+ |---|---|---|---|
53
+ | `read_leagues()` | League metadata with region info | -- | |
54
+ | `read_seasons()` | Seasons with region/league/season IDs | -- | |
55
+ | `read_season_stages()` | Stages within seasons | -- | Group stages, knockouts, etc. |
56
+ | `read_schedule()` | Match schedule | `[league, season, game]` | |
57
+ | `read_missing_players()` | Injured/suspended players | `[league, season, game, team, player]` | Includes reason and status |
58
+ | `read_events()` | Detailed Opta event stream | `[league, season, game]` | See output formats below |
59
+
60
+ **Event output formats** (`output_fmt` parameter):
61
+ - `'events'`: DataFrame with columns: game_id, period, minute, second, expanded_minute, type, outcome_type, team, player, x, y, end_x, end_y, goal_mouth_y/z, blocked_x/y, qualifiers, is_touch, is_shot, is_goal, card_type, related_event_id
62
+ - `'raw'`: Original WhoScored JSON dict
63
+ - `'spadl'`: SPADL format (requires socceraction package)
64
+ - `'atomic-spadl'`: Atomic-SPADL format (requires socceraction package)
65
+ - `'loader'`: Returns socceraction OptaLoader instance
66
+ - `None`: Cache only, no return
67
+
68
+ ## ClubElo (sd.ClubElo)
69
+
70
+ Source: clubelo.com. HTTP-based CSV API. Does not filter by league (global data). Elo scores available from 1939 (provisional before 1960).
71
+
72
+ **Methods**:
73
+
74
+ | Method | Returns | Index | Notes |
75
+ |---|---|---|---|
76
+ | `read_by_date(date=None)` | All team Elo ratings for a date | `team` | Columns: rank, country, level, elo, from, to, league |
77
+ | `read_team_history(team)` | Full Elo timeline for one club | `from` (date) | `max_age` parameter controls cache age |
78
+
79
+ ## ESPN (sd.ESPN)
80
+
81
+ Source: ESPN's public API (site.api.espn.com). HTTP-based JSON API.
82
+
83
+ **Methods**:
84
+
85
+ | Method | Returns | Index | Notes |
86
+ |---|---|---|---|
87
+ | `read_schedule()` | Match schedule | `[league, season, game]` | date, home/away team, game_id |
88
+ | `read_matchsheet()` | Team-level match stats | `[league, season, game, team]` | venue, attendance, capacity, box score stats |
89
+ | `read_lineup()` | Detailed lineups | `[league, season, game, team, player]` | position, formation_place, sub times, per-player stats |
90
+
91
+ ## Sofascore (sd.Sofascore)
92
+
93
+ Source: sofascore.com API. HTTP-based JSON API.
94
+
95
+ **Methods**:
96
+
97
+ | Method | Returns | Index | Notes |
98
+ |---|---|---|---|
99
+ | `read_leagues()` | League metadata with league_id | -- | |
100
+ | `read_seasons()` | Season metadata with season_id | -- | |
101
+ | `read_league_table()` | Standings | `[league, season]` | MP, W, D, L, GF, GA, GD, Pts |
102
+ | `read_schedule()` | Match schedule | `[league, season, game]` | round, week, date, scores, game_id |
103
+
104
+ ## SoFIFA (sd.SoFIFA)
105
+
106
+ Source: sofifa.com (FIFA video game ratings). HTTP-based, 1-second rate limit. Uses `versions` parameter instead of seasons -- maps to FIFA game database snapshots. Options: `'latest'` (default), `'all'`, specific version ID, or list of IDs.
107
+
108
+ **Methods**:
109
+
110
+ | Method | Returns | Index | Notes |
111
+ |---|---|---|---|
112
+ | `read_leagues()` | League metadata | -- | |
113
+ | `read_versions()` | Available FIFA editions/updates | -- | version_id for each snapshot |
114
+ | `read_teams()` | Teams per league per version | -- | |
115
+ | `read_players(team=None)` | Player lists with player_id | -- | |
116
+ | `read_team_ratings()` | 23 team attributes | -- | overall, attack, midfield, defence, build_up_speed/dribbling/passing, etc. |
117
+ | `read_player_ratings()` | 36 individual player attributes | -- | overall, potential, crossing, finishing, dribbling, pace, etc. |
118
+
119
+ **Player rating attributes**: overall, potential, crossing, finishing, heading_accuracy, short_passing, volleys, dribbling, curve, fk_accuracy, long_passing, ball_control, acceleration, sprint_speed, agility, reactions, balance, shot_power, jumping, stamina, strength, long_shots, aggression, interceptions, positioning, vision, penalties, composure, defensive_awareness, standing_tackle, sliding_tackle, GK stats.
120
+
121
+ ## MatchHistory (sd.MatchHistory)
122
+
123
+ Source: football-data.co.uk. HTTP-based CSV files. Historical match results with extensive betting odds.
124
+
125
+ **Methods**:
126
+
127
+ | Method | Returns | Index | Notes |
128
+ |---|---|---|---|
129
+ | `read_games()` | Comprehensive match data | `[league, season, game]` | See columns below |
130
+
131
+ **Key columns**: league, date, home/away team, referee, full-time/half-time goals, shots, shots on target, fouls, corners, cards, plus betting odds from multiple bookmakers (Bet365, Betway, Pinnacle, etc.). Full column documentation at football-data.co.uk/notes.txt.
@@ -0,0 +1,54 @@
1
+ # soccerdata
2
+
3
+ ## Overview
4
+
5
+ soccerdata is a Python library that scrapes football data from popular websites and returns pandas DataFrames with consistent, matching column names and identifiers across datasets. Data is downloaded on demand and cached locally. Licensed under Apache 2.0, authored by Pieter Robberechts (KU Leuven).
6
+
7
+ - **Install**: `pip install soccerdata` (optional: `pip install soccerdata[socceraction]` for SPADL conversion)
8
+ - **Python**: >=3.9, <3.14
9
+ - **Key dependencies**: pandas, lxml, seleniumbase (Selenium scrapers), tls_requests, html5lib, unidecode
10
+
11
+ ## Supported Sources
12
+
13
+ | Scraper Class | Source | Access Method | Rate Limit | Coverage |
14
+ |---|---|---|---|---|
15
+ | `sd.FBref` | fbref.com (Opta/StatsBomb data) | HTTP (tls_requests) | 7s between requests | Top leagues + many more, 2017/18+ for detailed stats |
16
+ | `sd.Understat` | understat.com | HTTP (JSON API) | None explicit | Big 5 European leagues only |
17
+ | `sd.WhoScored` | whoscored.com (Opta data) | Selenium (Chrome) | 5s + 0-5s random | Top leagues, detailed event data |
18
+ | `sd.Sofascore` | sofascore.com | HTTP (JSON API) | None explicit | Wide coverage |
19
+ | `sd.ESPN` | ESPN public API | HTTP (JSON API) | None explicit | Top leagues |
20
+ | `sd.ClubElo` | clubelo.com | HTTP (CSV API) | None explicit | All European clubs, 1939-present |
21
+ | `sd.SoFIFA` | sofifa.com (FIFA game ratings) | HTTP | 1s between requests | All FIFA-rated leagues |
22
+ | `sd.MatchHistory` | football-data.co.uk | HTTP (CSV download) | None | 25+ leagues, results + betting odds |
23
+
24
+ ## Built-in League Support
25
+
26
+ | League ID | FBref | Understat | WhoScored | ESPN | Sofascore | ClubElo | MatchHistory | SoFIFA |
27
+ |---|---|---|---|---|---|---|---|---|
28
+ | ENG-Premier League | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
29
+ | ESP-La Liga | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
30
+ | ITA-Serie A | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
31
+ | GER-Bundesliga | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
32
+ | FRA-Ligue 1 | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
33
+ | INT-World Cup | Yes | - | Yes | - | - | - | - | - |
34
+ | INT-European Championship | Yes | - | Yes | - | Yes | - | - | - |
35
+
36
+ Custom leagues can be added via `~/soccerdata/config/league_dict.json`.
37
+
38
+ ## Architecture
39
+
40
+ Two base reader classes:
41
+ - **`BaseRequestsReader`** -- uses `tls_requests` (TLS-fingerprint-resistant HTTP client, not standard `requests`). Used by: FBref, Understat, ClubElo, ESPN, Sofascore, SoFIFA, MatchHistory.
42
+ - **`BaseSeleniumReader`** -- uses SeleniumBase with undetected-chromedriver (Chrome). Used by: WhoScored only. Constructor accepts `path_to_browser` and `headless` (default `False`).
43
+
44
+ Both inherit from abstract `BaseReader` which provides caching, proxy management, league/season selection.
45
+
46
+ ## Limitations and Caveats
47
+
48
+ - **Web scraping is fragile**: The README warns "any changes to the scraped websites will break the package."
49
+ - **Anti-scraping / IP blocking**: WhoScored uses Incapsula protection (code checks for "Incapsula incident ID"). FBref enforces strict 7s rate limits. All HTTP scrapers use TLS-fingerprint-resistant requests.
50
+ - **WhoScored requires Chrome browser**: Slower, more resource-intensive, harder to run in CI. Headless mode may trigger anti-bot detection.
51
+ - **Limited built-in leagues**: Only 5+3 leagues built-in. Understat only covers Big 5 European leagues.
52
+ - **No authentication required**: All scrapers use public-facing websites/APIs.
53
+ - **FBref multi-level columns**: Returns DataFrames with multi-level column headers (category + stat) that can be tricky to work with.
54
+ - **SoFIFA uses FIFA game versions**, not real-world seasons. The `versions` parameter maps to specific game database snapshots.
@@ -0,0 +1,157 @@
1
+ # soccerdata Usage Guide
2
+
3
+ ## Installation
4
+
5
+ ```bash
6
+ pip install soccerdata
7
+
8
+ # With SPADL conversion support (for WhoScored events)
9
+ pip install soccerdata[socceraction]
10
+ ```
11
+
12
+ ## Basic Usage Pattern
13
+
14
+ All scrapers follow the same pattern: instantiate with league(s) and season(s), then call `read_*()` methods to get DataFrames.
15
+
16
+ ```python
17
+ import soccerdata as sd
18
+
19
+ # Single league, single season
20
+ fbref = sd.FBref('ENG-Premier League', '2023-2024')
21
+
22
+ # Multiple leagues and seasons
23
+ fbref = sd.FBref(
24
+ ['ENG-Premier League', 'ESP-La Liga'],
25
+ ['2022-2023', '2023-2024']
26
+ )
27
+
28
+ # Fetch data -- returns pandas DataFrames
29
+ schedule = fbref.read_schedule()
30
+ team_stats = fbref.read_team_season_stats(stat_type="passing")
31
+ player_stats = fbref.read_player_season_stats(stat_type="standard")
32
+ ```
33
+
34
+ ## Season Format
35
+
36
+ Very flexible parsing -- all of these are equivalent:
37
+
38
+ ```python
39
+ '2021', '21', '2020-2021', '2020/2021', '2020-21', '20-21', '20/21', 2021
40
+ ```
41
+
42
+ Internally normalised to either single-year or multi-year format depending on league calendar. If no seasons are specified, defaults to the last 5 seasons.
43
+
44
+ ## DataFrame Structure
45
+
46
+ All data returns as pandas DataFrames with **MultiIndex**. Common index patterns:
47
+
48
+ | Index Pattern | Used For |
49
+ |---|---|
50
+ | `[league, season, game]` | Match-level data |
51
+ | `[league, season, team]` | Team season aggregates |
52
+ | `[league, season, team, player]` | Player season stats |
53
+ | `[league, season, game, team, player]` | Player match stats |
54
+
55
+ **Game ID format**: `"YYYY-MM-DD home_team-away_team"` (constructed by `make_game_id()`).
56
+
57
+ **Column naming**: All columns converted to snake_case. FBref often has multi-level column headers (level 0 = stat category, level 1 = specific stat).
58
+
59
+ ## Team Name Standardization
60
+
61
+ All scrapers apply `TEAMNAME_REPLACEMENTS` to normalize team names across sources. Add custom mappings in `~/soccerdata/config/teamname_replacements.json`:
62
+
63
+ ```json
64
+ {
65
+ "StandardName": ["Alternative1", "Alternative2"]
66
+ }
67
+ ```
68
+
69
+ ## Caching and Configuration
70
+
71
+ **Directory structure** (default `~/soccerdata/`):
72
+ - `data/` -- cached data files, subdirectories per source (FBref/, Understat/, etc.)
73
+ - `config/` -- `league_dict.json`, `teamname_replacements.json`
74
+ - `logs/` -- `info.log`, `error.log` (rotating, 1MB max, 10 backups)
75
+
76
+ **Environment variables**:
77
+
78
+ | Variable | Description | Default |
79
+ |---|---|---|
80
+ | `SOCCERDATA_DIR` | Base directory | `~/soccerdata` |
81
+ | `SOCCERDATA_NOCACHE` | Disable reading cache (`true`/`1`/`t`) | `false` |
82
+ | `SOCCERDATA_NOSTORE` | Disable writing cache | `false` |
83
+ | `SOCCERDATA_MAXAGE` | Max cache age in days | None (no expiry) |
84
+ | `SOCCERDATA_LOGLEVEL` | Logging level | `INFO` |
85
+
86
+ **Constructor cache parameters**:
87
+
88
+ ```python
89
+ # Ignore cached data, always re-download
90
+ fbref = sd.FBref('ENG-Premier League', no_cache=True)
91
+
92
+ # Do not save downloaded data to disk
93
+ fbref = sd.FBref('ENG-Premier League', no_store=True)
94
+
95
+ # Custom cache directory
96
+ fbref = sd.FBref('ENG-Premier League', data_dir=Path('/tmp/soccerdata'))
97
+ ```
98
+
99
+ For current (incomplete) seasons, cached data is automatically re-fetched. Use `force_cache=True` on read methods to override this and use cached data even for current seasons.
100
+
101
+ ## Proxy Support
102
+
103
+ ```python
104
+ # Tor proxy on default port 9050
105
+ fbref = sd.FBref('ENG-Premier League', proxy='tor')
106
+
107
+ # Custom SOCKS5 proxy
108
+ fbref = sd.FBref('ENG-Premier League', proxy='socks5://host:port')
109
+
110
+ # Rotating proxy list
111
+ fbref = sd.FBref('ENG-Premier League', proxy=['proxy1', 'proxy2'])
112
+
113
+ # Custom callable returning a proxy URL
114
+ fbref = sd.FBref('ENG-Premier League', proxy=my_proxy_function)
115
+ ```
116
+
117
+ ## Rate Limits and Retries
118
+
119
+ | Scraper | Rate Limit | Retry Behaviour |
120
+ |---|---|---|
121
+ | FBref | 7s between requests | Up to 5 retries |
122
+ | WhoScored | 5s + 0-5s random delay | 5 retries with exponential backoff (0s, 10s, 20s, 30s, 40s) |
123
+ | SoFIFA | 1s between requests | Up to 5 retries |
124
+ | Others | No explicit rate limit | Up to 5 retries |
125
+
126
+ ## WhoScored-Specific Setup
127
+
128
+ WhoScored requires a browser for Selenium-based scraping:
129
+
130
+ ```python
131
+ ws = sd.WhoScored(
132
+ 'ENG-Premier League', '2023-2024',
133
+ path_to_browser='/usr/bin/chromium', # optional, auto-detects
134
+ headless=False # headless may trigger anti-bot detection
135
+ )
136
+
137
+ # Get Opta event data
138
+ events = ws.read_events(output_fmt='events') # DataFrame
139
+ raw = ws.read_events(output_fmt='raw') # JSON dict
140
+ spadl = ws.read_events(output_fmt='spadl') # SPADL format (needs socceraction)
141
+ ```
142
+
143
+ ## Cross-Source Workflow Example
144
+
145
+ ```python
146
+ import soccerdata as sd
147
+
148
+ # Combine FBref stats with Understat xG data
149
+ fbref = sd.FBref('ENG-Premier League', '2023-2024')
150
+ understat = sd.Understat('ENG-Premier League', '2023-2024')
151
+
152
+ # Team names are automatically standardized across sources
153
+ team_stats = fbref.read_team_season_stats(stat_type="standard")
154
+ xg_stats = understat.read_team_match_stats()
155
+
156
+ # Match on standardized team names in the index
157
+ ```
package/package.json CHANGED
@@ -1,16 +1,27 @@
1
1
  {
2
2
  "name": "football-docs",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Searchable football data provider documentation for AI coding agents. Like Context7 for football data.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "football-docs": "bin/serve.js"
8
8
  },
9
+ "engines": {
10
+ "node": ">=20"
11
+ },
9
12
  "scripts": {
10
13
  "build": "tsc",
14
+ "prebuild": "npm run check",
15
+ "check": "tsc --noEmit",
11
16
  "dev": "tsx src/index.ts",
12
17
  "ingest": "tsx src/ingest.ts",
13
- "start": "node dist/index.js"
18
+ "crawl": "tsx src/crawl.ts",
19
+ "discover": "tsx src/crawl.ts --discover",
20
+ "lint": "biome check src/",
21
+ "lint:fix": "biome check --write src/",
22
+ "prepublishOnly": "npm run build && npm run ingest",
23
+ "start": "node dist/index.js",
24
+ "test": "vitest run"
14
25
  },
15
26
  "keywords": [
16
27
  "football",
@@ -34,19 +45,27 @@
34
45
  "url": "git+https://github.com/withqwerty/football-docs.git"
35
46
  },
36
47
  "dependencies": {
48
+ "@apidevtools/swagger-parser": "^12.1.0",
37
49
  "@modelcontextprotocol/sdk": "^1.12.1",
38
- "better-sqlite3": "^11.9.1"
50
+ "@mozilla/readability": "^0.6.0",
51
+ "better-sqlite3": "^11.9.1",
52
+ "linkedom": "^0.18.12",
53
+ "turndown": "^7.2.2"
39
54
  },
40
55
  "devDependencies": {
56
+ "@biomejs/biome": "^2.4.9",
41
57
  "@types/better-sqlite3": "^7.6.13",
42
58
  "@types/node": "^22.15.2",
59
+ "@types/turndown": "^5.0.6",
43
60
  "tsx": "^4.19.4",
44
- "typescript": "^5.8.3"
61
+ "typescript": "^5.8.3",
62
+ "vitest": "^4.1.2"
45
63
  },
46
64
  "files": [
47
65
  "dist/",
48
66
  "bin/",
49
67
  "data/docs.db",
50
- "docs/"
68
+ "docs/",
69
+ "providers.json"
51
70
  ]
52
71
  }
package/providers.json ADDED
@@ -0,0 +1,170 @@
1
+ {
2
+ "$comment": [
3
+ "Football Docs Provider Registry",
4
+ "",
5
+ "Source types:",
6
+ " llms_txt - llms.txt or llms-full.txt (purpose-built for LLMs, highest priority)",
7
+ " readthedocs - ReadTheDocs site (structured, version-pinned)",
8
+ " github_docs - GitHub repo docs/ folder or README",
9
+ " api_docs - Standalone API documentation site",
10
+ " curated - Hand-written by football-docs contributors",
11
+ "",
12
+ "To add a new provider: add an entry here, then run: npm run crawl -- --provider <name>"
13
+ ],
14
+ "providers": {
15
+ "statsbomb": {
16
+ "description": "Event data provider with free open-data repository",
17
+ "version": null,
18
+ "package": { "type": "github", "repo": "statsbomb/open-data" },
19
+ "sources": [
20
+ { "url": "https://github.com/statsbomb/open-data", "type": "github_docs" },
21
+ { "type": "curated", "note": "Cross-provider comparisons, coordinate conversion formulas" }
22
+ ],
23
+ "last_crawled": null
24
+ },
25
+ "opta": {
26
+ "description": "Stats Perform event data (F24/F7 XML format)",
27
+ "version": null,
28
+ "package": null,
29
+ "sources": [
30
+ { "type": "curated", "note": "No public docs available; compiled from community knowledge" }
31
+ ],
32
+ "last_crawled": null
33
+ },
34
+ "wyscout": {
35
+ "description": "Hudl/Wyscout event and match data",
36
+ "version": null,
37
+ "package": null,
38
+ "sources": [
39
+ { "type": "curated", "note": "Compiled from API documentation and community knowledge" }
40
+ ],
41
+ "last_crawled": null
42
+ },
43
+ "sportmonks": {
44
+ "description": "REST API for football fixtures, standings, and events",
45
+ "version": null,
46
+ "package": null,
47
+ "sources": [
48
+ { "url": "https://docs.sportmonks.com/football", "type": "api_docs" },
49
+ { "type": "curated", "note": "Event type mappings and field descriptions" }
50
+ ],
51
+ "last_crawled": null
52
+ },
53
+ "kloppy": {
54
+ "description": "Python library for standardising football data across providers",
55
+ "version": "3.16.0",
56
+ "package": { "type": "pypi", "name": "kloppy" },
57
+ "sources": [
58
+ { "url": "https://kloppy.pysport.org/", "type": "readthedocs" },
59
+ { "url": "https://github.com/PySport/kloppy", "type": "github_docs" }
60
+ ],
61
+ "last_crawled": null
62
+ },
63
+ "socceraction": {
64
+ "description": "Python library for SPADL representation and VAEP/xT action valuation",
65
+ "version": "1.5.3",
66
+ "package": { "type": "pypi", "name": "socceraction" },
67
+ "sources": [
68
+ { "url": "https://socceraction.readthedocs.io/en/latest/", "type": "readthedocs" },
69
+ { "url": "https://github.com/ML-KULeuven/socceraction", "type": "github_docs" }
70
+ ],
71
+ "last_crawled": null
72
+ },
73
+ "soccerdata": {
74
+ "description": "Python library for scraping football data from popular websites",
75
+ "version": "1.8.8",
76
+ "package": { "type": "pypi", "name": "soccerdata" },
77
+ "sources": [
78
+ { "url": "https://soccerdata.readthedocs.io/en/latest/", "type": "readthedocs" },
79
+ { "url": "https://github.com/probberechts/soccerdata", "type": "github_docs" }
80
+ ],
81
+ "last_crawled": null
82
+ },
83
+ "mplsoccer": {
84
+ "description": "Python library for drawing soccer pitches and visualisations with matplotlib",
85
+ "version": "1.6.1",
86
+ "package": { "type": "pypi", "name": "mplsoccer" },
87
+ "sources": [
88
+ { "url": "https://mplsoccer.readthedocs.io/en/latest/", "type": "readthedocs" },
89
+ { "url": "https://github.com/andrewRowlinson/mplsoccer", "type": "github_docs" }
90
+ ],
91
+ "last_crawled": null
92
+ },
93
+ "databallpy": {
94
+ "description": "Python library for loading, synchronising, and analysing tracking and event data",
95
+ "version": "0.7.2",
96
+ "package": { "type": "pypi", "name": "databallpy" },
97
+ "sources": [
98
+ { "url": "https://databallpy.readthedocs.io/en/latest/", "type": "readthedocs" },
99
+ { "url": "https://github.com/Alek050/databallpy", "type": "github_docs" }
100
+ ],
101
+ "last_crawled": null
102
+ },
103
+ "api-football": {
104
+ "description": "REST API for football data via RapidAPI (fixtures, standings, players, live scores)",
105
+ "version": "3",
106
+ "package": null,
107
+ "sources": [
108
+ { "url": "https://www.api-football.com/documentation-v3", "type": "api_docs" }
109
+ ],
110
+ "last_crawled": null
111
+ },
112
+ "football-data-org": {
113
+ "description": "REST API for football competition data (v4) — fixtures, standings, teams, players",
114
+ "version": "4",
115
+ "package": null,
116
+ "sources": [
117
+ { "url": "https://docs.football-data.org/general/v4/index.html", "type": "api_docs" }
118
+ ],
119
+ "last_crawled": null
120
+ },
121
+ "fpl": {
122
+ "description": "Fantasy Premier League unofficial API — player stats, fixtures, gameweeks, transfers",
123
+ "version": null,
124
+ "package": null,
125
+ "sources": [
126
+ { "type": "curated", "note": "Unofficial undocumented API; compiled from community sources" }
127
+ ],
128
+ "last_crawled": null
129
+ },
130
+ "floodlight": {
131
+ "description": "Python library for spatial football data analysis (tracking, pitch control, metrics)",
132
+ "version": null,
133
+ "package": { "type": "pypi", "name": "floodlight" },
134
+ "sources": [
135
+ { "url": "https://floodlight.readthedocs.io/en/latest/", "type": "readthedocs" },
136
+ { "url": "https://github.com/floodlight-sports/floodlight", "type": "github_docs" }
137
+ ],
138
+ "last_crawled": null
139
+ },
140
+ "thesportsdb-v1": {
141
+ "description": "TheSportsDB v1 API — free tier, search-based endpoints for teams, players, events, livescores",
142
+ "version": "1",
143
+ "package": null,
144
+ "sources": [
145
+ { "url": "https://www.thesportsdb.com/api/spec/v1/openapi.yaml", "type": "openapi" },
146
+ { "url": "https://www.thesportsdb.com/documentation", "type": "api_docs" }
147
+ ],
148
+ "last_crawled": null
149
+ },
150
+ "thesportsdb-v2": {
151
+ "description": "TheSportsDB v2 API — paid tier, expanded endpoints with schedules, statistics, lookups",
152
+ "version": "2",
153
+ "package": null,
154
+ "sources": [
155
+ { "url": "https://www.thesportsdb.com/api/spec/v2/openapi.yaml", "type": "openapi" },
156
+ { "url": "https://www.thesportsdb.com/documentation", "type": "api_docs" }
157
+ ],
158
+ "last_crawled": null
159
+ },
160
+ "free-sources": {
161
+ "description": "Free football data sources (FBref, Understat, ClubElo, football-data.co.uk)",
162
+ "version": null,
163
+ "package": null,
164
+ "sources": [
165
+ { "type": "curated", "note": "Overview and access patterns for free data sources" }
166
+ ],
167
+ "last_crawled": null
168
+ }
169
+ }
170
+ }