Metadata-Version: 2.4
Name: espn_odds_scraper
Version: 0.2.1
Summary: A package for scraping historical and live MLB odds from ESPN's public API
Author-email: Oronto <vile319@gmail.com>
Project-URL: Homepage, https://github.com/Oronto/espn_odds_scraper
Project-URL: Bug Tracker, https://github.com/Oronto/espn_odds_scraper/issues
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pandas>=1.0.0
Requires-Dist: requests>=2.0.0
Requires-Dist: MLB-StatsAPI>=1.0.0
Dynamic: license-file

# espn_odds_scraper

Scrape historical and live MLB odds from ESPN's public (undocumented) API. No API key, no Selenium — plain JSON requests.

Successor to `mlb_odds_scraper` (OddsPortal/Selenium based). ESPN carries per-book odds (DraftKings, FanDuel, Caesars, MGM, Bet365, ...; older seasons carry BOVADA, 5Dimes, etc.), moneyline + run line + total in a single request per game, and timestamped line-movement history on its consensus feed.

**Coverage:** solid from ~2015 onward. Earlier seasons exist but are degraded (moneylines often missing).

## Install

```bash
pip install espn_odds_scraper
```

## Usage

```python
from espn_odds_scraper import scrape_espn_mlb, scrape_espn_mlb_years

# One day, every book — one row per game x sportsbook
df = scrape_espn_mlb("2023-07-14")

# Date range, only certain books
df = scrape_espn_mlb("2023-07-01", "2023-07-31", providers=["DraftKings", "FanDuel"])

# With full timestamped line movement (opt-in, ~3 extra requests per game)
odds, movement = scrape_espn_mlb("2023-07-14", include_history=True)

# Whole seasons
df = scrape_espn_mlb_years(2018, 2024)
```

### Odds DataFrame columns

`game_id, game_datetime (UTC), status, completed, home_team_abbr, away_team_abbr, home_team_name, away_team_name, home_team_espn_id, away_team_espn_id, home_score, away_score, provider_id, provider, home_ml, away_ml, spread (home line), home_spread_odds, away_spread_odds, total, over_odds, under_odds, open_* (8 cols), close_* (8 cols), moneyline_winner, spread_winner`

For completed games, per-book odds are the lines frozen at game time — effectively **closing lines**. In-game "Live Odds" feeds are dropped by default (`exclude_live=False` to keep them).

### Opening / closing lines & line movement

ESPN's data comes in two eras:

- **2024+ (ESPN BET / DraftKings era):** each book carries real `open_*` and `close_*` snapshots (moneyline, spread + prices, total + prices) directly in the odds row — no extra requests. Fewer books, though (often just one).
- **≤2023 (multi-book era):** `open_*`/`close_*` are empty (ESPN stored junk there), but full **timestamped line movement** exists on the consensus feed:

```python
from espn_odds_scraper import fetch_line_history, get_open_close

movement = fetch_line_history("401472391")   # timestamped rows per market
oc = get_open_close(movement)                # one row per market: open_* and close_*
```

Movement rows: `game_id, market (moneyline/spread/total), line_date (UTC), away_odds, home_odds, over_odds, under_odds, line`. First row per market is the opener, last is the closer. ESPN dropped this feed after the 2023 season.

### Drop-in compatibility with mlb_odds_scraper

```python
from espn_odds_scraper import to_legacy_format, clean_game_data

legacy = to_legacy_format(df)  # game_date, game_datetime, home_team/away_team
                               # (statsapi ids), home_odds/away_odds, scores, abbrs
merged = clean_game_data(cleaned_schedule, legacy)  # same merge helper as before
```

## Request footprint

- 1 request per day (schedule + scores)
- 1 request per game (all books, all markets)
- optional: 3 requests per game (line movement)

A full season is roughly 2,600 requests without history. Requests run through a thread pool (`max_workers=8` by default). Be polite; this is an undocumented API.

## License

MIT
