真正干净的正文需定位语义化容器如<main>或<article>,过滤script/style等干扰标签后调用get_text(),并注意XPath和浏览器选区的安全提取逻辑。

用 BeautifulSoup 定位语义化容器再调 get_text()
直接对整个 soup 调用 get_text(),大概率把导航栏、页脚、广告文案全塞进来。真正干净的正文,基本都藏在 <main>、<article> 或带 content/post/entry 类名的 <div> 里。
优先尝试这行定位逻辑:
soup.find("main") or soup.find("article") or soup.find("div", class_=re.compile(r"content|post|entry|body"))
- 如果目标网站结构稳定(比如教育平台固定用
div.dnevnik-lesson__task),就写死 CSS 选择器:soup.select_one("div.dnevnik-lesson__task") - 定位后立刻调
.get_text(separator="\n", strip=True):换行符分隔段落,首尾空白全清掉 - 别跳过过滤步骤——即使选对了父容器,里面还可能混着
<script>、<style>、<nav>,它们的文本会污染结果
提取前必须 decompose() 干扰标签
不是 extract(),也不是手动 clear(),是 decompose()——它连节点对象本身都销毁,内存更干净,且不会留下空占位。
执行这句再提取:
立即学习“前端免费学习笔记(深入)”;
for tag in soup(["script", "style", "nav", "footer", "header", "aside"]): tag.decompose()
-
<script>和<style>里的内容对文本无意义,但它们的get_text()可能返回大段 JS 字符串或 CSS 注释 -
<nav>和<header>常含重复链接文本,和正文语义无关 - 图标类标签(如
<i class="icon-download"></i>)没文本,不影响get_text(),不用管
避免 text() 在 XPath 中误判文本节点
用 //span[@class='meta']/text() 经常拿不到想要的日期或作者,不是 XPath 写错了,而是 HTML 里 text() 返回的是节点集合,XPath 1.0 只取第一个——而第一个往往是换行符、空格,或者分隔符 | 前面那段。
当目标文本紧跟某个已知分隔符(比如 |、:、—)时,改用:
substring-after(//span[@class='meta'], "| ")
- 先确保整个
span的字符串值完整(包含所有子文本),再切分 - 比遍历所有
text()节点 + 条件过滤更稳,尤其适合时间戳、作者名这类“分隔符后即目标”的场景 - 注意:XPath 表达式需配合 lxml 使用,
html.parser不支持substring-after
用户选中文本必须检查 rangeCount 再取值
在浏览器中监听用户高亮操作,window.getSelection().toString() 看似简单,但一拖跨两个 <p> 就可能漏字;一松手还没触发事件,getRangeAt(0) 就直接抛 IndexSizeError。
安全读取三步不能少:
const sel = window.getSelection(); if (sel.rangeCount === 0) return; const range = sel.getRangeAt(0); const text = range.toString().trim();
- 永远先判断
rangeCount > 0,否则 iOS Safari 或旧版微信 WebView 会静默失败 - 不要用
sel.anchorNode.textContent—— 它不反映真实选区,跨元素时错乱率极高 - 需要位置信息?必须用
range.getBoundingClientRect(),anchorOffset是字符偏移,不是像素坐标
最易被忽略的一点:动态渲染页面中,选区可能在 DOM 更新后失效,getBoundingClientRect() 返回的矩形区域也得在最新帧里重新取一次。



















