All chapters21
On this page

HHY Extension · Current version v1.7.1

HTML Extension and Crawler Framework

Combine the official HTML extension with a safe frontier for URL normalization, discovery, recursive deduplication, and bounded static crawling.

What the HTML extension is

The official html 0.2.0 package is a process extension with no network or filesystem effects. Lexbor parses untrusted HTML, evaluates CSS selectors, and extract_report returns batch rows with explicit truncation metadata.

Build and install the HTML extension

sh
brew install jansson lexbor
make -C extensions/html
./build/hhy install ./extensions/html
./build/hhy list
Complete signaturePurpose
html.text(String html, String selector, Map?) -> String?Read normalized text from the first matching node
html.text_all(String html, String selector, Map?) -> List<String>Read text from every matching node
html.attr(String html, String selector, String name, Map?) -> String?Read an attribute from the first matching node
html.attr_all(String html, String selector, String name, Map?) -> List<String>Read an attribute from every matching node
html.exists(String html, String selector) -> BoolTest whether a selector matches
html.extract(String html, String selector, Map schema, Map?) -> List<Map>Parse once and project repeated records through a schema
OptionCallablesBehavior
trim: Booltext, text_all, attr, attr_allTrim surrounding whitespace; enabled by default
max_results: Inttext_all, attr_all, extractDefaults to 1000; hard limit 10000

The extension limits input to 768 KiB, keeping protocol messages bounded. extract schema fields use { selector, value: "text" } or { selector, value: "attr", name }; an empty selector reads the current root. It does not return DOM handles: Protocol 1 transports only JSON-shaped values, so html.extract performs parsing and projection inside one extension call.

From HTML extraction to a safe crawler

The static spider composes separate responsibilities: Runtime url_resolve normalizes relative references; the HTML extension discovers links; a depth frontier checks domains, paths, page and queue budgets, and fingerprints before admission; the HTTP layer blocks SSRF at the resolved connection address.

CapabilityCurrent implementation
url_resolve(url, base?)Returns url, scheme, host, port, path, query, and a stable fingerprint
Link discoveryfollow_selector extracts href values and feeds the next frontier
Frontier and deduplicationDepth batches with bounded concurrency and pre-admission fingerprint deduplication
Hard boundariesDomains, path prefixes, depth, pages, frontier size, and links per page
SSRF protectionReject loopback, private, and link-local socket addresses, including redirects

Scope and explicit boundaries

The crawler supports an in-memory or atomically checkpointed frontier, strict configuration-matched resume, and send_to response files. An optional Playwright renderer executes JavaScript separately from the side-effect-free Lexbor extension and applies domain plus DNS private-network checks to documents, redirects, and subresources.