``、
``
`` 等。本模块递归地把行内节点转成 Markdown,``
`` 通过
``resolve_image`` 回调决定最终链接(本地化或远程)。
"""
import re
from urllib.parse import urljoin
from bs4 import NavigableString, Tag
from config import BASE_URL
_WS_RE = re.compile(r"\s+")
def _abs(href: str) -> str:
"""把相对地址补成绝对 URL。"""
if not href:
return ""
return urljoin(BASE_URL + "/", href)
def _inline(node, resolve_image) -> str:
"""递归转换单个节点为 Markdown 文本。"""
if isinstance(node, NavigableString):
return str(node)
if not isinstance(node, Tag):
return ""
name = node.name
if name == "br":
return "\n"
inner = "".join(_inline(c, resolve_image) for c in node.children)
if name in ("strong", "b"):
s = inner.strip()
return f"**{s}**" if s else ""
if name in ("em", "i"):
s = inner.strip()
return f"*{s}*" if s else ""
if name == "a":
text = inner.strip()
href = _abs(node.get("href", ""))
return f"[{text}]({href})" if text else ""
if name == "img":
src = _abs(node.get("src", ""))
alt = (node.get("alt") or "").strip()
return resolve_image(src, alt)
# span / div / font / u 等容器:透传内容
return inner
def blocks_to_markdown(elements, resolve_image) -> str:
"""把文章正文的块级元素(```` 与块级 ``
`` 等,按文档顺序)转为 Markdown。
源页面的图表是 ``container-narrow`` 的直接子 ``
``,与 ``
`` 交替出现,
因此必须按顺序遍历而非只取 ``
``。块内空白折叠为单空格,块间用空行分隔。
"""
blocks: list[str] = []
for el in elements:
text = _WS_RE.sub(" ", _inline(el, resolve_image)).strip()
if text:
blocks.append(text)
return "\n\n".join(blocks)