Comparison

View on GitHub

← Back to docs

Comparison

Use JustHTML when you want browser-grade HTML parsing, safe-by-default sanitization, CSS selectors, transforms, text extraction, and serialization in one pure-Python package.

Use a different tool when one narrow requirement matters more than the whole pipeline: maximum throughput, a BeautifulSoup-specific API, XPath-heavy XML work, or integration with an existing lxml tree.

At a Glance

ToolHTML5 parsing [1]SpeedQueryBuildSanitizeNotes
JustHTML
Pure Python
✅ 100%⚡ Fast✅ CSS selectorselement()✅ Built-inCorrect, secure, easy to install, and fast enough.
selectolax
Python wrapper of C-based Lexbor
✅ 100%🚀 Very Fast✅ CSS selectorscreate_node()❌ Needs sanitizationVery fast.
Chromium
browser engine
🟡 95.0% [2]🚀 Very FastCurrent browser-harness result.
turbohtml
Python wrapper of a C core
🟡 94.2%🚀 Very Fast✅ CSS selectors, XPathE.* builder✅ Built-inBroad, compiled alternative with parsing, querying, and sanitization.
WebKit
browser engine
🟡 93.9% [2]🚀 Very FastCurrent browser-harness result.
Firefox
browser engine
🟡 93.1% [2]🚀 Very FastCurrent browser-harness result.
html5lib
Pure Python
🟡 82.3%🐢 Slow🟡 XPath (lxml)🟡 Tree API🔴 DeprecatedUnmaintained reference implementation; incomplete coverage of the tree-construction fixtures.
markupever
Python wrapper of Rust-based html5ever
🟡 79.4%🚀 Very Fast✅ CSS selectorsTreeDom .create_*()❌ Needs sanitizationFast, but many fixtures cases abort its current parser process.
html5_parser
Python wrapper of C-based Gumbo
🔴 47.8%🚀 Very Fast🟡 XPath (lxml)🟡 etree (lxml)❌ Needs sanitizationFast, but its public tree API loses information needed by many fixtures.
BeautifulSoup
Pure Python
🔴 0.3% (default)🐢 Slow🟡 Custom APInew_tag() API❌ Needs sanitizationWraps html.parser (default). Can use lxml or html5lib.
html.parser
Python stdlib
🔴 0.3%⚡ Fast❌ None❌ None❌ Needs sanitizationStandard library. Chokes on malformed HTML.
lxml
Python wrapper of C-based libxml2
🔴 0.9%🚀 Very Fast🟡 XPathetree / E-factory❌ Needs sanitizationFast but not HTML5 compliant. Context-fragment cases are skipped; supported cases still perform poorly. Don't use the old lxml.html.clean module!

[1]: Library correctness scores are counted against the web-platform-tests tree-construction tests. They were run locally at 2026-07-15 and cover 1,880 cases after excluding scripting-directed fixtures. JustHTML and Selectolax 0.4.11 passed all 1,880 cases; MarkupEver's score counts its 103 process-aborting cases as errors.

[2]: Current local rerun with justhtml-html5lib-tests-bench against WPT commit 4830edb. Chromium 143.0.7499.4, WebKit 26.0, and Firefox 144.0.2 were compared against 1,908 cases; the harness skips 12 #script-on cases but includes #script-off cases, so these scores are not directly comparable to the 1,880-case Python-parser scores above.

Why JustHTML

Most Python HTML projects start simple and then accumulate extra tools:

  • a parser for broken HTML
  • a sanitizer for user input
  • a selector engine
  • a serializer
  • linkification or cleanup filters
  • text or Markdown extraction

JustHTML keeps those operations on one DOM. That makes the behavior easier to reason about, especially when the input is untrusted.

from justhtml import JustHTML

doc = JustHTML("<p>Hello<script>alert(1)</script><a href='javascript:x'>link</a></p>", fragment=True)

print(doc.to_html(pretty=False))
# <p>Hello<a>link</a></p>

Sanitization happens before you query or serialize unless you explicitly disable it with sanitize=False.

When to Choose Another Tool

Choose selectolax when raw speed is the main requirement and the HTML is trusted or sanitized elsewhere.

Choose turbohtml when you want a compiled, all-in-one HTML toolkit and are comfortable depending on a native extension. Its feature set overlaps more with JustHTML's than the parser-only alternatives do.

Choose markupever or html5_parser when you specifically want their underlying parser engines or tree APIs and can accept their compatibility tradeoffs.

Choose BeautifulSoup when you want its forgiving, familiar scraping API and parser correctness is not the main risk.

Choose lxml when your project is already built around XPath, etree, or XML-style processing.

Choose nh3 when you only need fast sanitization and are happy with a Rust-backed dependency.

Choose html.parser when you need a tiny stdlib-only script for trusted input and HTML5 correctness does not matter.

Choose Bleach only for existing codebases that already depend on it. For new projects, prefer an actively maintained sanitizer path. See Migrating from Bleach.

Tradeoffs

JustHTML is pure Python. That makes it easy to install, inspect, debug, and run in environments like Pyodide, but it will not beat C or Rust parsers on raw throughput.

JustHTML sanitizes HTML output by default. That is the right default for user-generated content, CMS snippets, comments, scraped fragments, and transform pipelines that eventually return to a browser. If all of your input is trusted, pass sanitize=False.

JustHTML's sanitizer emits HTML-only output. SVG and MathML can still be parsed when sanitization is disabled, but sanitized output drops foreign-namespace content to keep the security model smaller and more reviewable.