应先用find()定位标题与正文容器,再用find_all()配合get_text(separator="\n", strip=true)分离内容;需提前decompose()干扰节点,动态内容须换selenium等工具解析。

用 find() 和 find_all() 分离标题与正文容器
标题和正文通常不在同一 DOM 层级,硬用 get_text() 一锅端会混在一起。必须先定位语义区域:标题大概率在 <h1></h1>~<h6></h6>、<title></title> 或带 headline/title 类的标签里;正文则多在 <main></main>、<article></article> 或含 content/post 的 <div> 中。
<p>实操建议:</p>
<ul><li>别只查 <code>h1 —— 有些页面用 <div class="page-title"> 包标题,得配合 <code>class_=re.compile(r"title|headline")
soup.find("main") or soup.find("article") or soup.find("div", class_=re.compile(r"content|post|entry"))
<div class="wrapper">),先 <code>decompose() 掉导航、侧栏等干扰节点,再分别提取子节点
用 get_text(separator="\n", strip=True) 控制输出格式
分离后若直接调 .text 或 .string,会丢掉换行、合并段落,导致“标题正文挤成一行”。get_text() 是唯一能保留渲染顺序分隔逻辑的方法。
关键点:
-
separator="\n"让每个块级元素(<p></p>、<h2></h2>、<li>)之间插入换行,避免粘连 -
strip=True去掉每个文本片段首尾空格/换行,否则可能得到"\n 标题内容\n "这种带缩进的脏数据 - 不要用
separator=" "处理中文——空格分隔会导致“第一段第二段”变成“第一段 第二段”,阅读时易误判为词组
过滤干扰节点再提取,否则正文里混着广告脚本
即使选对了 <main></main>,里面仍可能嵌着 <script></script>、<style></style>、<footer></footer>、<aside></aside>,它们的 get_text() 结果会污染正文输出(比如脚本里的注释、内联样式里的字符串)。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
正确做法是提取前就清理:
- 用
soup(["script", "style", "nav", "footer", "header", "aside"])批量选中 - 对每个匹配到的 tag 调用
.decompose()(不是.extract())——decompose()彻底销毁节点,不占内存,也不留空文本节点 - 图标类标签(如
<i class="icon-download"></i>)无文本内容,不影响get_text(),不用额外处理
动态内容或 JS 注入标题时,BeautifulSoup 本身无法解决
如果标题是通过 JS 动态写入(如 document.title = "新标题" 或 innerHTML 插入),BeautifulSoup 解析原始 HTML 拿不到它。这时候 get_text() 再准也没用。
应对方式只有两个:
- 换 Selenium 或 Playwright 加载完整页面,再取
driver.title和driver.find_element(By.TAG_NAME, "main").text - 若只是补全
<title></title>,可先用requests拿 HTML,解析出soup.title.string,再作为标题字段单独存,不参与正文拼接
结构化解析真正的难点不在“怎么切”,而在“切之前是否看清了 DOM 真实状态”——JS 渲染、异步加载、服务端模板注入,都会让静态解析结果和用户看到的不一致。这点容易被忽略。










