Skip to main content

soup5ever

A BeautifulSoup 4 tree builder backed by Rust's html5ever. Same HTML5 trees as BeautifulSoup(html, "html5lib"), 6–14x faster.

from bs4 import BeautifulSoup
import soup5ever

soup = BeautifulSoup(html, "html5ever")

Installation

pip install soup5ever

Wheels for Linux (x86_64, aarch64; glibc and musl) and macOS (arm64), one abi3 wheel per platform for CPython 3.10+. The only dependency is beautifulsoup4>=4.13; no Rust, libxml2 or html5lib needed.

Usage

Importing soup5ever registers the "html5ever" parser (also "soup5ever"). The generic features "html5" and "html" are registered at the lowest priority, so importing it doesn't change what BeautifulSoup(markup, "html5") or BeautifulSoup(markup) select.

The usual options work (from_encoding, element_classes, multi_valued_attributes, store_line_numbers, attribute_dict_class). Like html5lib, parse_only isn't supported.

Compatibility

The target is BeautifulSoup(html, "html5lib"); where html5lib and the HTML standard disagree, soup5ever follows the standard.

  • BS4's own tests for its html5lib builder: 93/93 pass.
  • html5lib-tests tree construction: 1,588/1,592 match the spec. Against html5lib the trees are identical in 1,417 cases; the other 175 are classified automatically (167 html5lib behind the spec, 4 BS4 html5lib-adapter bugs, 4 <selectedcontent> misses both share).
  • 182 targeted differential cases and ~23k fuzz inputs (triaged with Chromium): every remaining difference is an html5lib bug or listed below.

Differences from html5lib:

  • Current HTML standard where html5lib 1.1 (2020) is behind: the 2025 <select> rules, <template> in <head>, </p> in SVG/MathML, <main>/<summary>, <search>, <dialog>, ruby. See tests/corpus.py for each case.
  • BS4's html5lib adapter never applies the Noah's Ark clause (AttrList has no __eq__); soup5ever does.
  • Undeclared, valid UTF-8 bytes are decoded as UTF-8 (html5lib guesses windows-1252 without chardet). Decoding follows the WHATWG Encoding Standard, not Python's codecs.
  • Lone surrogates in a str become U+FFFD.
  • sourceline/sourcepos match html5lib for ~98.5% of elements.

Shared with html5lib: no parse_only, no Script/Stylesheet string subclasses, no <selectedcontent> cloning.

Experimental: html5ever-experimental

soup = BeautifulSoup(html, "html5ever-experimental")

Builds the same trees as "html5ever", 10–30% faster, by creating BeautifulSoup's objects without running their constructors (Tag.__init__, NavigableString.__new__): the extension sets the attributes those would set, once each and already linked into the tree.

That relies on BeautifulSoup internals, verified against beautifulsoup4 4.13–4.15:

  • The first parse checks that the installed BeautifulSoup still sets exactly the attributes soup5ever expects. If not, it warns once and falls back to the regular construction.
  • Custom element_classes with their own __init__/__new__/__setattr__/setup, __getattribute__ or properties for the attributes BS4 sets, attribute_dict_classes with their own __setitem__, and builder subclasses that override how tags are set up get the regular construction automatically.
  • What it can't detect: a BeautifulSoup release that keeps those attributes but changes what they mean.

The test suite compares every object's full state (vars() in order, value types, links) with "html5ever"'s over the whole corpus, the html5lib-tests and the fuzz inputs, and runs BS4's own builder tests against it. It is never selected through the generic "html5" or "html" features.

Benchmarks

BeautifulSoup(markup, parser) on an in-memory str, median of 7 rounds, 4-vCPU Linux VM, CPython 3.11:

document html5lib html5ever speedup
small page (3 KiB) 2.4 ms 250 µs 9.6x
large page (1.2 MiB) 888 ms 101 ms 8.8x
malformed tag soup 483 ms 34 ms 14.2x
deeply nested 243 ms 26 ms 9.3x
table-heavy 507 ms 69 ms 7.3x
SVG/MathML-heavy 323 ms 51 ms 6.4x

Parsing in Rust is 14–32% of soup5ever's time; the rest is BeautifulSoup's own object constructors. html5ever-experimental skips most of the constructor work (it has its own column in the benchmark output). To reproduce:

uv pip install -e .[dev]
python benchmarks/run.py

Development

uv venv venv && source venv/bin/activate
uv pip install -e .[dev]                # builds the Rust extension
python scripts/fetch_upstream_tests.py  # BS4's builder tests + html5lib-tests
pytest

Re-run uv pip install -e .[dev] after changing Rust code.

edwh fmt && edwh lint                   # Python (ruff)
cargo fmt && cargo clippy               # Rust (lint levels in Cargo.toml)

pytest includes a 3000-input differential fuzz run; pytest --fuzz 20000 --fuzz-seed 7 runs a bigger one.

License

MIT

Metadata

Release files for soup5ever 0.2.0

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

Source distribution (sdist)

Source distribution for soup5ever 0.2.0
File Size Uploaded
soup5ever-0.2.0.tar.gz 83.7 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for soup5ever 0.2.0
File
soup5ever-0.2.0-cp310-abi3-musllinux_1_2_x86_64.whl CPython 3.10 abi3 Linux musl 1.2+ x86-64 Details
soup5ever-0.2.0-cp310-abi3-musllinux_1_2_aarch64.whl CPython 3.10 abi3 Linux musl 1.2+ ARM64 Details
soup5ever-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
soup5ever-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details
soup5ever-0.2.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details

Total release size: 3.1 MB

Release files / soup5ever-0.2.0.tar.gz

Download URL soup5ever-0.2.0.tar.gz
Size 83.7 kB
Tags Source
SHA-256 checksum
How to use checksums
0689ea7d5371c164e28a0c709ce1c3ee193a135310310097590f8e7304adff4c
BLAKE2b-256 checksum
How to use checksums
30d5ea6b48b58ddba2dcd148672fa99ffaaea3dc668ba8147428f1086e9623d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / soup5ever-0.2.0-cp310-abi3-musllinux_1_2_x86_64.whl

Download URL soup5ever-0.2.0-cp310-abi3-musllinux_1_2_x86_64.whl
Size 629.8 kB
Tags CPython 3.10 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
06fe640d1ba43dfb4877431811d2ecc7bd67251281f0dc8d97c14be7af5ce1f0
BLAKE2b-256 checksum
How to use checksums
8396137a76de2d277d17814992ed1d7e16d65733ac45b5d889ddd8895442109c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / soup5ever-0.2.0-cp310-abi3-musllinux_1_2_aarch64.whl

Download URL soup5ever-0.2.0-cp310-abi3-musllinux_1_2_aarch64.whl
Size 612.2 kB
Tags CPython 3.10 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
cf8de880f3c1f9d7bbabcde31b0f55e58ad6a05416387cfd2e727280156964ee
BLAKE2b-256 checksum
How to use checksums
a7aeea3d32aa80107eeca6d80f76aa50153431c8de951aa641d5530e52597ade
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / soup5ever-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL soup5ever-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 631.5 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
012003c992e4128db81a264a560fe64ae54b189e4ad34901b0f78d748e764035
BLAKE2b-256 checksum
How to use checksums
01529e8a34fed6aa9b0c9b1ce3b1a49e16447bad14200585d6568af349142796
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / soup5ever-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL soup5ever-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 613.3 kB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
9d2fd6be4c907af1f18b895b07d894882a19d0f6cdc85dd4b646643b3212b950
BLAKE2b-256 checksum
How to use checksums
c289c593217236decf6d6bd4db61372fcac2c670403088f20621fd7626c19f81
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / soup5ever-0.2.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL soup5ever-0.2.0-cp310-abi3-macosx_11_0_arm64.whl
Size 569.2 kB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
22cf9b29d50ef17c2b5ea25fdc7083f9e1a1593b5370b2e21dc069e13885e5db
BLAKE2b-256 checksum
How to use checksums
95af2f7e6a223f234c4590a502ab4549fa82aa68e1a4a5e90c80fef1bb125f01
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release history Release notifications | RSS feed

This release

0.2.0 This release

6 release files

0.1.0

6 release files

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