Page Extract

Paste a URL, get clean readable text — nav, footer, script and style stripped, paragraphs kept only when they pass a word-count + link-density score — plus word count and reading time (200 wpm). Computed per call; the page below renders the pinned capture offline.

Source

Words

Reading time

Meta

Extracted text

Extraction keeps long, low-link-density paragraphs in document order; reference lists on reference-bearing pages remain part of the text (readability-style behaviour, documented in PROOF.md).

Live mode (CLI)

python3 page_extract.py --live <url> — fetches with a descriptive UA and prints the same report JSON; refuses (exit 4) on non-HTML, no-title, or <40-word pages.
Method. One keyless GET with a descriptive UA. A stdlib HTMLParser walk strips script/style/noscript/template text entirely, treats nav/header/footer/aside/form (plus table/figure) as chrome, and collects candidate paragraphs (p, li, blockquote, h1–h6, pre). A paragraph is kept when it has ≥25 words, link density (anchor words ÷ words) ≤ 50%, and score words×(1−density) ≥ 20. Word count is len(text.split()); reading time is ceil(words/200). The guard (check_extract.py --self-test, 11 bars) re-derives title, counts, and the 151-word nav-signature bar from the raw pinned fixture with its own naive parsers (no module import), byte-replays the report, and rejects 4 poisoned cases — each on its own bar — plus a doctored-fixture control. Pin: .