用正则提取 HTML 的局限
HTML 允许任意层嵌套、属性值里出现大于号、注释与脚本块里存在形似标签的内容,这些都不是正则能可靠处理的。正则适合的场合是结构已知且规整的片段,例如自己生成的模板输出或单行标题;面对真实网页,解析器才是正确工具。
基本信息
| 正则能做 | 抽取已知结构的单层片段、按标签名粗去标记、匹配跨行脚本块 |
|---|---|
| 正则做不了 | 嵌套配对、容错解析、属性解析(属性值可含大于号)、标签自动闭合 |
| 推荐工具 | html5lib、BeautifulSoup、lxml、DOMParser、Jsoup 等解析器 |
| 风险点 | 复杂的标签模式容易演变成回溯热点,处理网页时应限制输入长度 |
典型使用场景
- 抽取标题与元信息:页面结构简单且单行时可用,复杂页面改用解析器的选择器
- 粗去标记取纯文本:先移除脚本与样式块,再去标签,最后合并空白
- 移除脚本与样式:跨行匹配块级内容,注意不要误删正文中的同类文本
- 清洗邮件与富文本:只允许白名单标签时,应对解析树做删除而不是用正则替换
- 抽取属性值:属性可能被引号包裹、可能有换行,解析器更稳
有限可用的写法
有限可用的写法
# 单行标题:内容不含尖括号时可用,跨行与嵌套场景不成立
<title>([^<]*)</title>
# 移除脚本块:开启单行模式让点号匹配换行,用非贪婪限定范围
(?s)<script\b[^>]*>.*?</script>
# 粗去标签:属性值中含大于号时会提前截断,仅适合简单文本
<[^>]*>
# 正确做法:交给解析器构造文档树,再按需要取值或删除节点
soup = BeautifulSoup(html, 'html5lib'); text = soup.get_text(' ', strip=True)
for tag in soup(['script', 'style']): tag.decompose() # 先删脚本与样式再取文本需求与合适手段
| 需求 | 正则可行性 | 建议手段 |
|---|---|---|
| 取单个标签内容 | 单行且无嵌套时可用 | 解析器选择器更稳 |
| 嵌套元素配对 | 不可行 | 解析器 |
| 抽取属性值 | 不可靠 | 解析器按属性读取 |
| 移除脚本与样式 | 可行,需单行模式 | 解析树删除更安全 |
| 富文本白名单过滤 | 不可行 | 解析器加白名单策略 |
标签名与属性名大小写、属性引号可省略、布尔属性没有取值、名称空间前缀等写法让「用一条模式覆盖全部情况」不成立,遇到真实网页内容时优先选择解析器。
如果确实要对生成物使用正则(例如只处理自己模板产出的固定结构),请把这类模式当作契约写进测试:模板一变就应当由测试失败提醒,而不是线上静默取到空值。