Skip to main content


𖤐 domonic 𖤐

The browser DOM, in Python.

Generate HTML. Parse real pages. Query with CSS or XPath. Manipulate a browser-style DOM.
Use and learn real HTML, DOM and JavaScript-style APIs using Python code!

PyPI version Downloads Python version Python package Documentation License: MIT GitHub stars


domonic is a pure-Python implementation of the browser platform: a real DOM, HTML/SVG/XML generation, multiple HTML parsers, CSS selectors, XPath, and a large slice of the JavaScript and Web API surface — all as ordinary Python objects.

from domonic.html import *

page = html(
    body(
        h1("Hello, World!"),
        p("HTML as Python objects."),
        a("GitHub", _href="https://github.com"),
    )
)

print(page)
# <html><body><h1>Hello, World!</h1><p>HTML as Python objects.</p><a href="https://github.com">GitHub</a></body></html>

That tree is a real DOM — query and mutate it like you would in a browser:

page.querySelector("h1").textContent = "Hello, DOM!"     # mutate by selector
print([a.href for a in page.querySelectorAll("a")])       # ['https://github.com']

The same kind of tree comes back from parsed HTML:

from domonic import domonic

document = domonic.parseString("<h1>Hello</h1><a href='/docs'>Documentation</a>")
print(document.querySelector("h1").textContent)           # Hello

New here? Start with the examples gallery.


Recipes

Scrape a page — fetch and query in one call, real DOM underneath:

from domonic import scrape

page = scrape("https://example.com")
print(page.querySelector("h1").textContent)
print([a.href for a in page.querySelectorAll("a[href]")])

# Load external CSS into document.styleSheets and attach a Window when needed.
page = scrape("https://example.com", css=True, attach=True)
style = page.defaultView.getComputedStyle(page.querySelector("body"))

scrape() also takes a CSS selector=, a list of URLs, css=True to fetch and parse linked stylesheets, attach=True to wire document.defaultView, or to="text" | "json" | "pyml" — see the scraping guide. Porting Beautiful Soup code? from domonic.bs4 import BeautifulSlop wraps the same nodes with find_all, select and get_text.

Build a server-side component — functions that return DOM trees:

from domonic.html import a, article, h2, p

def card(title, body, href):
    return article(h2(title), p(body), a("Open", _href=href), _class="card")

print(card("Python DOM", "Generate HTML with Python objects.", "/docs"))

Stream a large response — render lazily instead of building one huge string:

from fastapi.responses import StreamingResponse
from domonic.html import body, html, table, td, tr

def rows():
    for i in range(50_000):
        yield tr(td(f"Row {i}"), td(f"Data {i}"))

page = html(body(table(rows())))
return StreamingResponse(page.stream(), media_type="text/html")   # chunks, not one blob

More task guides: scraping · server-side HTML · live DOM updates · parser performance · compiled SSR


Features

🏗️ Markup generation HTML5, SVG, XML, MathML, RSS, Atom, ODF, A-Frame, X3D and custom elements
🌳 DOM Document, Element, Node, NodeList, fragments, ranges, events, traversal, observers, shadow DOM and more
🔎 Querying CSS selectors and XPath, index-backed for repeated queries
📥 Parsing Multiple interchangeable parser backends
🌐 Web APIs URL, URLPattern, storage, messaging, workers, crypto, performance, permissions and more
🟨 JavaScript-like APIs Array, Date, Math, String, Number, Promise, timers, typed arrays and JSON helpers
⚡ CLI Query URLs, files or piped HTML with CSS and XPath
🧪 Experiments dQuery, d3-inspired utilities, diffdom, BeautifulSlop and other browser-inspired ideas

Not every API is browser-complete — the goal is to keep moving closer to the real standards. Python 3.10+.


Install

python3 -m pip install domonic          # or: pip install --upgrade domonic
from domonic.html import *
print(h1("hello world"))

Want only the command line tool? Install it isolated with pipx — see the CLI guide.


HTML that is actually Python

Tag names are the HTML names. Attributes are the HTML names with a leading underscore, so examples read like HTML with Python syntax:

from domonic.html import *

card = div(
    h2("domonic"),
    p("The browser DOM, in Python."),
    a("Documentation", _href="https://domonic.readthedocs.io"),
    _class="card",                         # _class -> class (avoids the keyword)
)

print(card)

label("Email", _for="email")              # _for -> for

div("hello", **{"_data-user-id": "42"})   # attributes that aren't valid identifiers

A real DOM

domonic elements are nodes in a document tree, not formatted strings.

from domonic.html import *
from domonic.dom import document

page = html(body(main(
    h1("Projects"),
    ul(li("domonic"), li("Blueberry"), li("ezcron")),
)))

page.querySelector("h1").textContent = "Open source projects"   # mutate

new_item = document.createElement("li")                         # create
new_item.textContent = "something new"
page.querySelector("ul").appendChild(new_item)                  # attach

domonic follows the WHATWG DOM and HTML standards where practical. Full API: DOM documentation.


Query with CSS or XPath

Browser-style selectors, straight against the tree:

page.querySelector("#content")
page.querySelectorAll("a[rel=nofollow]")
page.querySelectorAll("a[href$='.pdf']")
page.querySelectorAll("article > p:first-child")

for link in page.querySelectorAll("a"):
    print(link.href)

XPath works too — from Python (domonic.webapi.xpath, see the scraping guide) or straight from the terminal:

domonic -x https://example.com '//a/@href'
curl -s https://example.com | domonic -q 'a.cta' --attr href

Repeated queries over the same page are significantly faster. 🚀 Parser performance.


Parse HTML

from domonic import domonic

page = domonic.parseString("<!doctype html><article><h1>Hello from HTML</h1></article>")
print(page.querySelector("h1"))

To fetch and parse a live URL in one step, use scrape().

Parsing is fast. 🚀 Pick a backend for zero dependencies, malformed-HTML repair, or raw speed:

Backend Notes
html.parser Python standard library, no extra dependency
html5lib Pure Python, bundled with domonic, spec-accurate tree building
turbohtml Pure-Python WHATWG parser, direct DOM adaptation
selectolax · lxml_html · html5_parser · markupever Native / compiled parsers via a shared adapter
tl · reliq Opt-in native parsers, outside auto
expat Built in, for XML-like input
domonic.parseString(markup, parser="selectolax")   # pin one
domonic.set_default_parser("html.parser")           # or set a default
domonic.get_active_parser()                         # what "auto" chose

The default is parser="auto", which tries the fastest installed backend that can handle the input. Install notes, the full comparison, whitespace-fidelity details and benchmarks are in the parser performance guide.


Render back to markup

from domonic.html import div, h1, p, render

page = div(h1("Hello"), p("Rendered from a Python DOM."))

markup = str(page)                        # or: "".join(page.stream()) for chunks
render(f"{page}", "index.html")           # write to disk

Rendering is configurable through DOMConfig (GLOBAL_AUTOESCAPE, RENDER_OPTIONAL_CLOSING_TAGS, ATTRIBUTE_QUOTES, an opt-in render cache, …). See the DOM documentation.


More in domonic

Each of these is a package with its own docs

JavaScript-style APIs — Math, Array, Date, URL, Promise, timers…
from domonic.javascript import Math, Array, URL, setTimeout

Math.random()
Array(1, 2, 3).splice(1)                  # [2, 3]
URL("https://example.com:8000/blog#hello").port   # 8000
setTimeout(lambda: print("later"), 1000)

JavaScript documentation

Web APIs — fetch/XHR, storage, workers, crypto, sanitizer, streams, canvas…
from domonic.webapi.sanitizer import Sanitizer

Sanitizer().sanitizeToString('<p onclick="bad()">Hi <script>bad()</script></p>')
# <p>Hi </p>

Dozens of APIs (URL, URLPattern, Web Storage, History, File API, Web Crypto, Web Workers, WebSocket, SSE, Permissions, Performance, Scheduler, Compression Streams, Canvas/WebGL, custom elements, Shadow DOM, MutationObserver…). Browse the Web APIs

SVG, XML, MathML and more
from domonic.svg import svg, circle

print(svg(circle(_cx="50", _cy="50", _r="40"), _width="100", _height="100"))

Also XML, MathML, RSS, Atom, ODF, sitemaps and A-Frame / X3D.

Style — DOM-style property access
box = div("hello", _id="message")
box.style.backgroundColor = "black"
box.style.fontSize = "12px"
# <div id="message" style="background-color: black; font-size: 12px;">hello</div>

Style documentation

BeautifulSlop — a BS4-style API over domonic parsing

Familiar find, find_all, select, get_text and mutation methods, but the objects you get back are real domonic nodes — no wrapper Tag, no second tree. BeautifulSlop documentation

diffdom — minimal DOM patches for live updates
from domonic.diffdom import DiffDOM
from domonic.html import div, p

DiffDOM().diff(div(p("Version one")), div(p("Version two")))   # patch list

diffdom documentation

dQuery — a jQuery-inspired API
from domonic.dQuery import º

º("#test").append(º('<div class="child"></div>'))

It also serves as a demanding consumer of the DOM implementation. dQuery documentation

d3-inspired utilities
from domonic.d3 import *

A Python interpretation of useful parts of the d3 ecosystem, built on the JavaScript and DOM layers. d3 documentation

JSON utilities — data ⇄ HTML tables ⇄ CSV
import domonic.JSON as JSON

JSON.tablify([{"id": "01", "name": "some item"}])   # -> an HTML table
JSON.csvify(data, "data.csv")
JSON.csv2json("data.csv")

JSON documentation

Animation / tweening
from domonic.lerpy.tween import Tween
from domonic.lerpy.easing import Linear

Tween({"x": 0}, {"x": 10}, 6, Linear.easeIn).start()

tween documentation

Terminal APIs — Python wrappers for Unix commands
from domonic.terminal import ls, git

print(ls())
print(git("status"))

Windows users can use domonic.cmd. terminal documentation


Command line

domonic -q https://example.com 'a.cta' --attr href --first    # CSS query a URL
domonic --xpath-file ./page.html '//title'                    # XPath a local file
curl -s https://example.com | domonic -q 'h1' --text          # pipe HTML in
domonic -e 'html(body(h1("hello")))'                          # evaluate pyml
domonic -p myproject --server fastapi                         # scaffold a project

Full flag reference: CLI guide.


Server-side HTML

domonic elements are Python objects that render to markup, so they drop into FastAPI, Flask, Django, Sanic and others — see the servers documentation.

For views that only return HTML, @compiled makes rendering significantly faster — every request, including the very first: 🚀

from domonic import compiled
from domonic.html import div, h1, p

@compiled
def home(name="World"):
    return div(h1("Hello"), p(name))

print(home("Alice & Bob"))   # <div><h1>Hello</h1><p>Alice &amp; Bob</p></div>

Supported syntax, caching, route integration and how the compiler works are in the compiled-rendering guide.


Examples & projects

Working examples throughout the repo: github.com/byteface/domonic/tree/master/examples

Built with domonic:

  • domonic-libs — extends domonic further
  • myjs — a JavaScript interpreter in pure Python
  • Blueberry — a browser-based file OS / component example
  • ezcron — a cron viewer
  • bombdisposer — a small game
  • htmlx — a lightweight DOM-focused relative of domonic

Documentation

📚 domonic.readthedocs.io — API coverage, package guides and less common functionality · Release notes


Development & contributing

Contributions are welcome — fork, branch, add or update tests, open a PR.

python3 -m pip install -r requirements-dev.txt
make test                 # or: pytest tests

The tests double as executable examples of the API. See CONTRIBUTING.md for more.


⭐ If you find it useful, consider starring the project.

Documentation · PyPI · Examples · Releases

Metadata

Release files for domonic 1.8.3

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

Source distribution (sdist)

Source distribution for domonic 1.8.3
File Size Uploaded
domonic-1.8.3.tar.gz 905.8 kB Details

Built distribution (wheel)

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

Total release size: 1.6 MB

Release files / domonic-1.8.3.tar.gz

Download URL domonic-1.8.3.tar.gz
Size 905.8 kB
Tags Source
SHA-256 checksum
How to use checksums
36b3c2a78539544afff055147101927843353b9c0145c70a8db892255b3ae0d6
BLAKE2b-256 checksum
How to use checksums
c1d9d54dbab156add54bb4c2eed1dbb5d89f6142d08c4a279b9fd60cf4b96dc6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.12

Release files / domonic-1.8.3-py3-none-any.whl

Download URL domonic-1.8.3-py3-none-any.whl
Size 666.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
64e7c82c265c755efd932e6f3a13ce9258f9662baf9a0fc5ec6704e0af9ddfd3
BLAKE2b-256 checksum
How to use checksums
491336505a14689b75464df3d064daa560d94991435cfe6af0e68d354b6b5f84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.12

Release history Release notifications | RSS feed

1.8.5

2 release files

1.8.4

2 release files

This release

1.8.3 This release

2 release files

1.8.2

2 release files

1.8.1

2 release files

1.8.0

2 release files

1.7.1

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.9.11

2 release files

0.9.10

2 release files

0.9.9

2 release files

0.9.8

2 release files

0.9.7

2 release files

0.9.6

2 release files

0.9.5

2 release files

0.9.4

2 release files

0.9.3

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.5

2 release files

0.8.4

2 release files

0.8.3

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.9

2 release files

0.6.8

2 release files

0.6.7

2 release files

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.19

2 release files

0.3.18

2 release files

0.3.12

2 release files

0.3.11

2 release files

0.3.10

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

1 release file

0.3.1

1 release file

0.3.0

1 release file

0.2.18

1 release file

0.2.17

1 release file

0.2.16

1 release file

0.2.15

1 release file

0.2.14

1 release file

0.2.13

1 release file

0.2.12

1 release file

0.2.11

1 release file

0.2.10

1 release file

0.2.9

1 release file

0.2.8

1 release file

0.2.7

1 release file

0.2.6

1 release file

0.2.5

1 release file

0.2.4

1 release file

0.2.3

1 release file

0.2.2

1 release file

0.2.1

1 release file

0.2.0

1 release file

0.1.12

1 release file

0.1.11

1 release file

0.1.10

1 release file

0.1.9

1 release file

0.1.8

1 release file

0.1.7

1 release file

0.1.6

1 release file

0.1.5

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1.0

1 release file

0.0.9

1 release file

0.0.8

1 release file

0.0.7

1 release file

0.0.6

1 release file

0.0.5

1 release file

0.0.4

1 release file

0.0.3

1 release file

0.0.2

1 release file

0.0.1

1 release file

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