Skip to main content

web2textpy

Python reimplementation of the Web2Text pipeline for labeling HTML DOM nodes as content or boilerplate using paired (raw_html, clean_text) data.

Installation

uv add web2textpy

Quick Start

from datasets import load_dataset
from web2text import run_pipeline

ds = load_dataset("williambrach/html-boilerplate-labeled", split="test")
row = ds[0]

tree, extracted_text, metrics = run_pipeline(row["html"], row["text"])

print(extracted_text[:200])
print(metrics)

Get text from labeled HTML

from web2text import extract_text_from_labeled_html
text = extract_text_from_labeled_html(labeled_html_string)

Step-by-Step API

Each stage of the pipeline is exposed as a standalone function:

from web2text import build_cdom, extract_leaves, align, label_nodes, extract_text, evaluate

# 1. Parse HTML into a collapsed DOM tree
tree = build_cdom(html_string)

# 2. Extract ordered text-bearing leaf nodes
leaves = extract_leaves(tree)  # [(element, "normalized text"), ...]

# 3. Align leaf texts against ground-truth clean text
scores = align(leaves, clean_text)  # {leaf_id: 0.0-1.0 match score}

# 4. Label each node as "content" or "boilerplate"
tree = label_nodes(tree, scores, threshold=0.667)

# 5. Extract text from content-labeled nodes
result = extract_text(tree)

# 6. Evaluate against ground truth
metrics = evaluate(result, clean_text)
# => {'token_f1': 0.99, 'precision': 0.99, 'recall': 0.99, 'rouge1_f': 0.99, 'bleu': 98.5, 'chrf': 98.8}

How the Matching Algorithm Works

Given raw HTML and its known clean text, the algorithm determines which DOM nodes are content versus boilerplate in six steps:

  1. Simplify the DOM — strip non-content tags (<script>, <style>, etc.) and collapse single-child chains into a Collapsed DOM (CDOM) representation
  2. Collect leaf text — walk the CDOM, concatenate text from every leaf node into one source string with tracked character offsets
  3. Find anchors — identify 10-character substrings that appear exactly once in both the source and clean text, splitting the problem into independent segments
  4. DP alignment — for each segment between anchors, run character-level dynamic programming with affine gap penalties to map source characters to clean-text characters
  5. Score leaves — map alignment results back to leaf boundaries via stored offsets, giving each leaf a score: matched_chars / total_chars
  6. Label nodes — leaves scoring above 0.667 are labeled "content", the rest "boilerplate", with labels propagating upward to parents

Alignment pipeline: extract leaf texts → anchor matching → DP alignment → per-leaf scores

Dataset

Dataset: williambrach/html-boilerplate-labeled — ~4k pages from CleanEval, Dragnet, CETD, Readability, and others (3,985 pages total).

Source Train (ROUGE-1 F) Test (ROUGE-1 F)
readability 0.993 (92) 0.997 (23)
scrapinghub 0.991 (145) 0.996 (36)
cetd 0.993 (560) 0.987 (140)
google-trends-2017 0.986 (144) 0.995 (36)
cleanportaleval 0.985 (57) 0.971 (14)
cleaneval 0.985 (590) 0.991 (148)
dragnet 0.983 (1,103) 0.983 (276)
l3s-gn1 0.920 (497) 0.927 (124)
Overall 0.976 (3,188) 0.978 (797)

Sample counts in parentheses.

Original Work

Metadata

Release files for web2textpy 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for web2textpy 0.2.1
File Size Uploaded Provenance
web2textpy-0.2.1.tar.gz 158.3 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for web2textpy 0.2.1
File Interpreter ABI Platform
web2textpy-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 173.9 kB

Release files / web2textpy-0.2.1.tar.gz

Download URL web2textpy-0.2.1.tar.gz
Size 158.3 kB
Tags Source
SHA-256 checksum
How to use checksums
aac70309f8cb7328ed335b86a0eea9a666416d2fdd723732e4f9c7545f67a938
BLAKE2b-256 checksum
How to use checksums
3ce3f230ab891bf4182467bc5aa7fa1144b6c6710bd7ce56f6f96bd46ccd53b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.5.16

Release files / web2textpy-0.2.1-py3-none-any.whl

Download URL web2textpy-0.2.1-py3-none-any.whl
Size 15.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2cb7c2bda581acad264724878ed97087c2b76c7572b2275b937458aff2056b8a
BLAKE2b-256 checksum
How to use checksums
d7fbb735c7a3cb3190557ecbb43fa58fe235e991e0c5f86750eb587d9d4f3e07
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.5.16

Security for web2textpy 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page