Library / SDK
jaebradley/basketball_reference_web_scraper avatar
jaebradley/basketball_reference_web_scraper

basketball_reference_web_scraper: NBA stats from Basketball Reference

NBA Stats API via Basketball Reference

561 stars132 forksHTMLMIT

At a glance

What is it?
basketball_reference_web_scraper is a Python package that produces NBA data by scraping the Basketball Reference website and returning it as objects, with the whole client built on requests and lxml and released as a numbered version series on PyPI. It suits a developer who wants box scores, player and team information without an API key, and the constraint to plan around is that the output is only as good as the HTML it was parsed from.
Who is it for?
Adopt basketball_reference_web_scraper if you need NBA statistics for a project and do not want to hold an API key, since the package returns parsed objects rather than raw HTML. Do not adopt it for a workload that cannot tolerate a page layout change, because the parsers are tied to the markup of the site and a redesign becomes a release rather than a patch, and check first which Python versions you can run, since the package requires 3.10 or newer and excludes 4.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly HTML, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A client for a site with no API

The package describes itself as a Basketball Reference client that generates data by scraping the website, and the project name on PyPI is basketball_reference_web_scraper.

That framing is worth pausing on, because it defines the whole category. There is no official API for Basketball Reference, so a client built on scraping is not a fallback or a stopgap but the only shape the problem can take. What the library offers over writing your own scraper is a maintained set of parsers, and what it offers over a sports data provider is a different trade: no key, no per-call billing, and access to the full breadth of the site's pages, against the loss of any guarantee that a page will still look the same next quarter.

The project's own framing is friendly about its origins. The author calls Basketball Reference a great site, especially for a basketball stats nut like him, and hopes they do not get too pissed off at me for creating this. He also notes that he initially wrote this library as an exercise for creating his first PyPi package, hope you find it valuable.

That origin story explains a lot about the project as it stands. A first package that started as an exercise has become a version 4 line with a long list of contributors and a regular release cadence, which is one of the more common trajectories for a small library that fills a gap nobody else bothers to fill.

The library is MIT licensed, its primary language is recorded as HTML, which is a symptom of the scraping nature of the project rather than a statement about how the code is written, and the topic tags are basketball-reference, nba, python, web-scraper and web-scraping. The default branch is v4, so the major version lives in the branch name, and the last push was on 2026-10-22.

The release history shows the feature line

The release titles are the clearest account of what the project does, because each one names a single addition.

Version 4.22.1 is a fix for regex string syntax to eliminate a SyntaxWarning, published on 2026-07-27. Version 4.22.0, from 2026-07-15, adds support for inactive NBA teams. And version 4.21.0, from 2026-07-13, adds a contracts API for retrieving player contract information.

Three releases in a fortnight, which is a healthy cadence for a small library, and the titles are all in the same shape: a short description of one thing that changed.

The inactive teams support is a good example of the kind of thing only a scraper needs. A team that has folded still has historical pages on the site, and the site still links to them from index pages and from season pages. A library that parses those index pages has to know what to do with a name it does not recognise, and adding support for inactive teams means the parser can now represent a franchise that no longer plays rather than skipping it.

The contracts API is a different kind of addition. It is a new surface rather than a new page, which means the library has a stable concept of what an API is and can add to it. The presence of a contracts API alongside box scores and team and player data suggests the library is organised around named endpoints that each return structured objects.

The SyntaxWarning fix is the least interesting and the most instructive of the three. A regex string that triggers a SyntaxWarning is not broken, but it prints a warning on import or on use, and it is the kind of thing that Python's own deprecation warnings will turn into an error in a later version. Fixing it as a patch release rather than a minor one shows the author treats compatibility noise as something to clear rather than to schedule.

The package version in the manifest matches the latest release, 4.22.1, so the version is kept in one place and released through the normal packaging path.

A small dependency surface, which is the point

The runtime dependencies of the package are two, and they are the two you would write yourself.

The manifest declares lxml at 6.1.1 or newer and below 7, and requests at 2.34.2 or newer and below 3. There is no HTML parsing framework, no async client, no model library, no data validation layer and no date handling library. The package fetches pages with requests and parses them with lxml, and returns its own objects.

That is a deliberate and, for a scraper, correct choice. A scraping library that pulled in a heavyweight framework would inherit that framework's update cadence and its breaking changes, and the person using it would have to deal with dependency resolution problems in exchange for conveniences they may not use. Two dependencies with upper bounds, both pinned to a major version, is a package that will install cleanly next year.

The version constraints are worth reading closely because they show the maintenance discipline. Both are bounded above, so a breaking major release of either will not silently break the package, and both have a minimum that is recent, meaning the package tracks current versions rather than supporting ancient ones.

The Python requirement is equally tight. Requires-python is 3.10 or newer and below 4, and the classifiers list Python 3.10 through 3.14, each as a separate classifier. That is a package that supports every current Python version including the newest, and explicitly excludes Python 4, which does not exist yet but will be excluded on day one rather than after a breakage.

The metadata is minimal and personal. The author and maintainer is Jae Bradley, with the same email address for both roles, and the keywords list is NBA, Basketball, Basketball, Reference and basketball-reference.com, with Basketball repeated. The project URL block points at the documentation homepage, the repository, and separate issues and pull requests links, which is the standard modern layout.

How the project is built and tested

The build and test configuration in the manifest is modern and mostly readable, and it says how the project is put together.

The build backend is uv_build at 0.11.26 or newer, below 0.12.0, with a tool.uv section above it and a tool.uv.build-backend section below it. The module root is the repository root itself, with module-root set to an empty string, and there are separate exclude lists for the source distribution and for the wheel, both naming the tests and docs directories. That is the arrangement where the package lives in the repository root next to its own metadata, which is why there is a top-level `__init__.py` in the repository listing alongside the package directory.

The dependency groups section has a dev group with the tooling pinned exactly: codecov, mkdocs, mkdocs-material, pymdown-extensions, coverage, pytest and requests-mock. Every one is pinned with an exact version rather than a range, which is the practice for a development group where you want the same environment on every machine.

requests-mock is the entry worth noticing. It is the standard way to test HTTP code without hitting the network, and for a scraping library it is not optional. A test suite that called the real site would be slow, flaky and rude, and it would fail every time the site changed rather than when the parser was wrong. With the responses mocked, the tests check that the parser extracts the right values from a known page, which is a much sharper assertion.

The pytest configuration sets the pythonpath to the package directory, testpaths to tests, and an addopts list that starts with an import mode setting. The coverage configuration lives in a separate .coveragerc file, and there is a codecov badge in the README pointing at the v4 branch, so coverage is measured and reported rather than merely collected.

The scripts directory at the root holds the helper scripts, and there is a mkdocs.yml with a docs directory, which is how the documentation site is built. The manifest pins mkdocs-material and pymdown-extensions for that, so the documentation site uses the mkdocs-material theme together with the Python Markdown extensions.

What the documentation has to carry

The documentation for the package lives at a GitHub Pages site, and the README's only instruction is to see the documentation page for installing the package and API methods.

That is a short README by design, and the split it implies is the right one for a library of this kind. The README's job is to say what the thing is and who made it; the documentation's job is the API reference, which for a library with a dozen or more endpoints and dozens of data fields is a large document that does not belong in a repository README.

For a user of this library, the practical difficulty is different from the usual one. There is no key to obtain and no service to sign up for, so installation is the whole of the setup, and the documentation is about the shape of the returned data rather than about access.

The contributor list in the README is long, twelve names, which is worth noting for a package that began as an exercise in making a first PyPI release. Contributors include DaiJunyan, ecallahan5, Yotamho, ntsirakis, allanbelliti, krlu, aaronbannin, benjaminmesser, pepeefirat, PGats, jakeakopp and DigitalCurrensy. The kinds of contribution a scraping library attracts are the obvious ones: a new page type to parse, a fix to an existing parser when the site changes, and support for another team or a different era of the league.

The other thing worth knowing about a library in this category is that its failure mode is silent. If the page structure changes and a parser does not match, the library may return an empty field or a default rather than raising, and the caller gets plausible-looking wrong data. The presence of a coverage badge and a request-mocking test suite reduces that risk on the pages that are covered, and it does not reduce it at all on a page nobody thought to write a test for. That is the thing to keep in mind when you rely on it, and it is why the regular small releases that fix individual parsers matter more than the feature announcements do.

Editorial conclusion

Adopt basketball_reference_web_scraper if you need NBA statistics for a project and do not want to hold an API key, since the package returns parsed objects rather than raw HTML. Do not adopt it for a workload that cannot tolerate a page layout change, because the parsers are tied to the markup of the site and a redesign becomes a release rather than a patch, and check first which Python versions you can run, since the package requires 3.10 or newer and excludes 4.

Frequently asked questions

What is basketball_reference_web_scraper?

It is a Python package that acts as a Basketball Reference client, generating NBA data by scraping the website. It is MIT licensed, published on PyPI as basketball_reference_web_scraper, and the project homepage is jaebradley.github.io/basketball_reference_web_scraper.

What Python versions does basketball_reference_web_scraper support?

The package requires Python 3.10 or newer and excludes 4, with classifiers for Python 3.10, 3.11, 3.12, 3.13 and 3.14. Its only runtime dependencies are lxml at 6.1.1 or newer below 7 and requests at 2.34.2 or newer below 3.

What data can I get from the basketball_reference_web_scraper package?

NBA data parsed from Basketball Reference pages, returned as structured objects, including a contracts API for retrieving player contract information, which was added in version 4.21.0. Version 4.22.0 added support for inactive NBA teams so that historical franchises still appear in the parsed index and season pages.

How is the basketball_reference_web_scraper package tested?

The dev dependency group pins pytest, coverage, codecov and requests-mock, and requests-mock is what lets the HTTP calls be tested without hitting the live site. The pytest configuration sets the pythonpath to the package directory and testpaths to tests, and a codecov badge on the README reports coverage for the v4 branch.

How is the basketball_reference_web_scraper package built and published?

It uses the uv build backend, uv_build at 0.11.26 or newer and below 0.12.0, with the module root at the repository root. The tests and docs directories are excluded from both the source distribution and the wheel, and the version in pyproject.toml is 4.22.1.

Is basketball_reference_web_scraper still being maintained?

The repository is not archived and the last push was on 2026-10-22, on the v4 branch. Recent releases are 4.22.1 from 2026-07-27, 4.22.0 from 2026-07-15 and 4.21.0 from 2026-07-13, and the documentation is built with mkdocs and mkdocs-material.

Official sources

  1. jaebradley/basketball_reference_web_scraper on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jaebradley-basketball-reference-web-scraper.svg)](https://hysenlabs.com/projects/jaebradley-basketball-reference-web-scraper)