######################## 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 ``