Trafilatura kept 2 of 5 hidden notes from a help page. A visibility filter removes both.
We ran Trafilatura 2.3.1 on a help page with five notes a reader never sees. The extract kept the stylesheet-hidden note and the hidden-attribute note, and a small pre-filter removed both.
By David Discua
Measured in the lab
- 5
- hidden notes on the page
- 2
- kept by raw Trafilatura
- 0
- kept after the filter
- 24/24
- tests passed
- 24 of 24 tests passed, 0 skipped
- Raw extract keeps NOTA-CLASE and NOTA-HIDDEN
- Filtered extract keeps no notes and keeps the help text
- class="hidden" on its own passes Trafilatura's discard rule
- No API keys, and the CLI reads local files only
From reports/gate.json · run on October 19, 2026. trafilatura 2.3.1 (v2.3.1, e2f85c965662) on CPython 3.13.16 with beautifulsoup4 4.15.0; local keyless run, GitHub Actions not run yet
How it is wired
01/03A help page carries five notes a reader never sees.
Trafilatura is a Python library that pulls the main text out of a web page, so if you hand its output to a model, the model reads whatever Trafilatura keeps. We ran Trafilatura 2.3.1 on a local help page with five notes a reader never sees, and two of them came through in the extract. A small visibility filter that runs before Trafilatura removed both and left the help text in place.
The catch
The page is a Spanish help article about deleting an account, with one note per hiding method. Trafilatura dropped three of them: the paragraph with an inline display:none, the HTML comment, and the JSON inside a script tag. It kept a paragraph hidden by a class rule in the page's own stylesheet (NOTA-CLASE) and one that carries the hidden attribute (NOTA-HIDDEN).
Trafilatura's discard XPath at the pinned commit decides from the element itself. It matches display:none written in a style attribute, and it matches class names and ids against a pattern such as ' hidden| hide'. It never reads the stylesheet, so a class whose only job is .solo-ia{display:none} in a <style> block looks like ordinary text. It never checks the hidden attribute either.
The class pattern has a second gap. A paragraph with class="hidden" and no other class in front of it also passes, because the pattern expects a space before hidden. On our second fixture, controles.html, the raw extract kept NOTA-CLASEHIDDEN and NOTA-CLASE.
The filter has limits of its own. It reads simple class selectors only, so descendant selectors, comma groups, attribute selectors and media queries stay in the page. White-on-white text, opacity:0, font-size:0 and off-screen text are out of scope. On controles.html the filter kept NOTA-CLASEHIDDEN, because no rule in that page's stylesheet hides the .hidden class.
What we ran (keyless)
git clone https://github.com/SkilledDragonCorp/oculto-trafilatura-estilo.git
cd oculto-trafilatura-estilo
uv sync --frozen
uv run --frozen pytest -v
uv run --frozen vis-extract fixtures/ayuda.html --raw
uv run --frozen vis-extract fixtures/ayuda.html
uv run --frozen python scripts/report.py
From reports/gate.json, run on October 19, 2026:
| Field | Value |
|---|---|
| Pin | trafilatura==2.3.1, tag v2.3.1, commit e2f85c96 |
| Runtime | CPython 3.13.16, beautifulsoup4 4.15.0 |
| Tests | 24 passed, 0 failed, 0 skipped, in 2.78 s |
ayuda.html raw | NOTA-CLASE, NOTA-HIDDEN |
ayuda.html filtered | no notes |
controles.html raw | NOTA-CLASEHIDDEN, NOTA-CLASE |
controles.html filtered | NOTA-CLASEHIDDEN |
controles-aviso.html raw | NOTA-CLASE |
vis-extract fixtures/ayuda.html --raw prints the two notes and exits with code 4. Without --raw it prints a count of 0 and exits with code 0, and the test suite checks that the sentence Para borrar tu cuenta is still in the filtered text. This was a local run on Linux. One test starts a child process under unshare --net and checks that a connect to an outside address fails. The workflow also defines a gitleaks scan, pip-audit and osv-scanner, and a relocated copy of Trafilatura's own build job. GitHub Actions has not run any of them yet, so we have no CI result to report.
How it is wired
extract_raw calls trafilatura.extract on the local HTML string, the same call the upstream quickstart makes, without fetch_url. visible_html parses the page with BeautifulSoup and removes comments, script, style, template and noscript elements, anything with the hidden attribute or aria-hidden="true", inline display:none and visibility:hidden, and elements whose class the page's own <style> block marks hidden. extract_visible runs Trafilatura on what is left. The CLI reads one .html file under fixtures/ or the OS temp directory, rejects URLs, and stops at 2 MB, so nothing is fetched or sent.
Minilab (open source)
Upstream is adbar/trafilatura (6,999 stars, Apache-2.0, Python, as of October 20, 2026). The lab is MIT. Save a page of your own as .html in fixtures/, run vis-extract on it with and without --raw, and compare the two counts.
Run it yourself
SkilledDragonCorp/oculto-trafilatura-estilo
Clone, install and run the report with no API keys. The numbers above are what that run writes.
uv sync --frozen && uv run --frozen python scripts/report.pySkilledDragon is not affiliated with Trafilatura or its authors. Numbers are from our own keyless lab run; GitHub Actions has not run these jobs yet, so re-run the report before relying on them. Marks belong to their owners.
All labs