A daily record of how many people are held by the Philadelphia Department of Prisons, collected from the city's daily headcount and census page and stored in this repository as data files.
See it: st215.github.io/JailJawn — one glyph for every person held, a timeline you can scrub, and what the numbers say.
The city publishes one day at a time and does not include this data in its open data portal. This repository is the history. It started as a civic hackathon project with the City of Philadelphia and a way to learn Python; the city gave permission to collect the page.
| File | What it holds |
|---|---|
census.csv |
One row per census day, every figure as a column. Start here for charts and spreadsheets. |
data/YYYY-MM-DD.json |
One record per census day with the five tables from the page. |
raw/YYYY-MM-DD.html |
The page as captured, so any day can be re-parsed. |
debug/ |
Page captures from before 2.0.0. Kept as the archive those days were re-parsed from. |
legacy/ |
The 2013–2017 census from the project's first scraper, 138 days, converted from its Firebase export. See legacy/README.md. |
feed.xml, feed.json, latest.json |
Subscribe to new census days. See SCHEMA.md. |
The file name is the census date printed on the page, not the day it was collected. See SCHEMA.md for every field, what a blank cell means, and which checks each record has passed.
Coverage runs from 2025-04-04. Days the city did not post, or the scraper missed, are simply absent.
A GitHub Actions workflow runs twice a day and:
- Opens the page in headless Chromium. The tables are rendered in the browser by a small app the city hosts, so plain HTTP returns nothing.
- Saves the page to
raw/. - Parses the five tables, identifying each by its exact header row.
- Validates the result. The census date must be real and new, every table and row must be present, no cell may be the page's pre-load placeholder, and the total must be plausible. A record that fails is not stored and the run fails loudly.
- Writes the JSON record, rebuilds
census.csv, and commits. If the city has not posted a new day yet, nothing is committed.
Arithmetic that does not close (the city has published figures that did not add up) is stored as a warnings field on the record rather than refusing the day.
Requires uv.
git clone https://github.com/ST215/JailJawn.git
cd JailJawn
uv sync
uv run playwright install chromium
uv run jailjawn scrape # fetch today's census and store it
uv run jailjawn scrape --dry-run # fetch and validate, write nothing
uv run jailjawn scrape --html raw/2026-09-07.html # parse a saved page
uv run jailjawn validate data/*.json # re-check stored records
uv run jailjawn export # rebuild census.csv from data/
uv run pytest # run the testsjailjawn backfill re-parses every capture in debug/ and writes a proof report to build/. It was used once, for 2.0.0, and is kept in case the parser ever changes again.
site/ is a static page with no build step. It fetches census.csv from this repository when it loads, so it is always current, and falls back to the copy deployed with it. The crowd on the front page is laid out with pretext, vendored in site/vendor/. GitHub Pages deploys it whenever site/ changes on master.
To work on it locally:
python3 -m http.server 8000 --directory site
# then open http://localhost:8000/- 1.0.0 is the last hand-written version, tagged as a record of the original project.
- 1.1.0 fixed a timeout that had started failing the daily run.
- 2.0.0 rewrote the parser, corrected a table-mapping bug present in every earlier file, re-parsed the full history from the saved pages, added validation, the CSV, tests, and the raw archive. The release notes carry the backfill report.
The data is public domain (CC0): figures the city published, collected here, offered as is with no warranty. The code is MIT. Credit is appreciated but not required: "JailJawn by Stanley Griggs II, github.com/ST215/JailJawn". See LICENSE.
For programs and people building on it: llms.txt describes every file in one page, datapackage.json is a Frictionless Data descriptor, CITATION.cff gives a citation, and the site carries schema.org Dataset markup. The daily record can be queried in a browser with Datasette Lite.
Stanley Griggs, stanleygriggs.com, @ST215. Issues and pull requests are welcome.
Everyone who has contributed since the 2013 hackathon, across every repository the project has lived in, is listed in CONTRIBUTORS.md.