Coverage for src/lilbee/crawler/markdown.py: 100%
12 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-14 11:46 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-14 11:46 +0000
1"""HTML to markdown conversion, owned by lilbee rather than by the fetcher backend.
3Fetching a page and converting it are separate jobs. Keeping the conversion here
4means a fetcher backend only has to return HTML, and the conversion runs where
5lilbee can await it instead of inside the backend's own call stack.
6"""
8from __future__ import annotations
10import re
12# Mirrors crawl4ai's own <base href> derivation (async_webcrawler) verbatim so a
13# silenced re-conversion resolves relative links the way an un-silenced crawl would.
14# A real HTML parser here would resolve differently and diverge from the backend;
15# keep this in sync with crawl4ai instead.
16_BASE_HREF = re.compile(r"<base\s[^>]*href\s*=\s*[\"']([^\"']+)[\"']", re.IGNORECASE)
19def base_url_for(html: str, url: str, redirected_url: str | None = None) -> str:
20 """The URL relative links resolve against: a ``<base href>`` if the page sets one."""
21 match = _BASE_HREF.search(html)
22 if match:
23 return match.group(1)
24 return redirected_url or url
27def html_to_markdown(html: str, base_url: str) -> str:
28 """Convert *html* to markdown, resolving relative links against *base_url*.
30 Imports its backend on call: this is the one place lilbee depends on a
31 third-party HTML-to-markdown implementation.
32 """
33 from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator
35 result = DefaultMarkdownGenerator().generate_markdown(html, base_url=base_url)
36 return str(result.raw_markdown or "")