htmlq: CSS-Select HTML Like jq for HTML
htmlq applies a CSS selector to HTML on stdin and prints the matching elements, their text, or a chosen attribute.
Scraping a value out of an HTML page with grep is fragile. htmlq parses the DOM and lets you select with the same CSS you would write in the browser.
What it does
htmlq reads HTML from stdin, matches a CSS selector, and prints the matching subtree by default. --text prints inner text only, --attribute <name> prints one attribute per match, and -p pretty-prints the HTML.
Common usage
# extract all link hrefs
curl -s https://example.com | htmlq --attribute href a
# get the page title text
curl -s https://example.com | htmlq --text title
# pretty-print a matched element
curl -s https://example.com | htmlq -p '.content'Options
| Flag | What it does |
|---|---|
| --text, -t | Print only the text content of matches |
| --attribute <name> | Print the value of this attribute per match |
| -p, --pretty | Pretty-print the output HTML |
| -w, --ignore-whitespace | Strip insignificant whitespace |
| -f, --filename <file> | Read HTML from a file instead of stdin |
| -b, --base <url> | Resolve relative URLs against this base |
In CI
Smoke-test a deployed page by asserting on its DOM: curl -s "$URL" | htmlq --text "h1" and compare to the expected heading, or pull a build hash out of a meta tag to confirm the right version is live. It is sturdier than grepping raw HTML.
Common errors in CI
htmlq: command not found: install with cargo install htmlq or a release binary. A selector that matches nothing prints empty output and exits 0, so an HTML error page can pass a check silently; assert the output is non-empty. Passing the URL as an argument does nothing because htmlq reads stdin; pipe curl into it. Malformed HTML is parsed leniently (it will not error), which can yield surprising matches.