########################
Find and rewrite links
########################
Work with the URLs in a page: enumerate and absolutize every link, canonicalize a single URL, and turn bare URLs and
emails into anchors.
***********************************************
Enumerate and absolutize every link in a page
***********************************************
Iterating ```` by hand misses the URLs in ``srcset``, a ```` redirect, and CSS
``url()``/``@import``. :meth:`~turbohtml.Node.links` finds them all, and :meth:`~turbohtml.Node.resolve_links` rewrites
them absolute against a base URL in place:
.. testcode::
doc = turbohtml.parse('x
')
doc.resolve_links("https://example.com/dir/")
for link in doc.links():
print(link.element.tag, link.attribute, link.url)
.. testoutput::
p style https://example.com/dir/hero.png
a href https://example.com/dir/a/b.html
For a one-off transform (rewriting a CDN host, signing URLs), pass a function to :meth:`~turbohtml.Node.rewrite_links`;
returning ``None`` leaves a link untouched.
******************************
Clean and canonicalize a URL
******************************
To recognize two spellings of the same page -- for deduplication, cache keys, or a crawl frontier -- canonicalize them
with :func:`turbohtml.extract.normalize_url`. It applies the WHATWG URL standard's normalization (case, default ports,
``..`` segments, percent-encoding) and drops known tracking parameters, sorting the rest:
.. testcode::
from turbohtml.extract import normalize_url
print(normalize_url("HTTPS://Example.ORG:443/a/../page?utm_source=rss&b=2&a=1"))
.. testoutput::
https://example.org/page?a=1&b=2
For URLs scraped out of markup, :func:`turbohtml.extract.clean_url` first scrubs HTML damage (stray whitespace,
``&``, a truncating quote) and answers ``None`` for anything that is not a fetchable web URL, so a scraping pipeline
can filter and normalize in one call. :class:`turbohtml.extract.UrlCleaning` carries the knobs: a strict query-parameter
allowlist, trailing-slash folding, fragment stripping, and a URL-based language filter.
:func:`turbohtml.extract.extract_links` runs the whole pipeline over a page -- parse, collect anchors, resolve against
the base, clean, deduplicate:
.. testcode::
from turbohtml.extract import extract_links
page = 'a b'
print(sorted(extract_links(page, "https://site.example/")))
.. testoutput::
['https://other.example/b', 'https://site.example/a']
*********************************
Turn URLs and emails into links
*********************************
To linkify user-entered text the way `bleach.linkify `_ did, use
:func:`turbohtml.clean.linkify`. It parses the HTML, so it links only in text the reader sees, never inside an existing
````, a ``