正则匹配失败主因是忽略文本真实结构,如换行、空格、html标签干扰;需用re.s跨行、预清洗、非贪婪捕获、re.m多行匹配,并在dom复杂时切换beautifulsoup。

正则表达式匹配失败的常见原因
多数人写完 re.findall() 拿不到结果,不是正则写错了,而是忽略了原始文本的实际结构。比如网页里目标内容被换行、空格或 HTML 标签隔开,而你写的正则默认不跨行、不忽略空白。
典型错误现象:re.findall(r'价格:(\d+)', html) 在
价格:<br><span>199</span>这种结构下完全失效。
- 用
re.DOTALL让.匹配换行符 - 用
re.S简写替代re.DOTALL - 避免直接匹配 HTML 标签,优先用
re.sub(r']+>', '', html)预清洗(简单场景) - 调试时先用
print(repr(html[100:200]))查看真实字节,别只靠浏览器“查看源码”
提取带单位/格式的数字(如“¥199.00”、“库存:3件”)
这类数据关键在「边界控制」和「非贪婪捕获」。贪心匹配容易吃掉后续内容,导致截断或漏匹配。
示例:从 原价:¥299.00,现价:¥199.00(立减¥100.00) 中分别提取三个价格:
import re
text = "原价:¥299.00,现价:¥199.00(立减¥100.00)"
prices = re.findall(r'¥(\d+\.\d{2})', text) # → ['299.00', '199.00', '100.00']
# 注意:\d+\.\d{2} 比 \d+\.?\d* 更稳,避免匹配到 "¥100" 或 "¥100." 这类不完整值
- 单位前置时,把单位写进正则但用括号只捕获数字部分
- 中文单位(如“件”“台”“GB”)需加
u前缀或确保文件编码为 UTF-8,否则re.compile(r'(\d+)件')可能报错 - 用
re.search()替代re.findall()当只需首个匹配(性能更好,且避免空列表异常)
处理多行混合格式的文本块(如商品参数表)
参数表常以“键:值”形式存在,但换行不规律、冒号后有空格或缩进,甚至夹杂无用行。这时单行正则容易断裂。
推荐策略:先用 re.split(r'\n\s*\n', text) 切分逻辑段落,再对每段用 re.findall(r'^([^:\n]+):([^:\n]+)$', block, re.M) 提取键值对。
-
re.M(MULTILINE)让^和$匹配每行首尾,而非整个字符串首尾 - 中文冒号
:和英文冒号:是不同字符,必须明确区分;混用时可用[::] - 若值中含换行(如“描述:这是一款……\n支持多语言”),需改用
re.search(r'描述:((?:.|\n)*?)(?=\n\S+:|$)', text)非贪婪跨行捕获
为什么不用正则而选 BeautifulSoup?
当目标结构稳定、嵌套深或依赖标签属性(如 <div class="price">),硬刚正则会越来越脆弱。不是正则不行,而是维护成本陡增。<p>一个信号:你开始写 <code>r'<div>]*class="[^"]*price[^"]*"[^>]*>(.*?)</div>' 并反复调 re.S | re.I,就该切到 BeautifulSoup 了。
-
re适合提取纯文本中的模式化片段(日期、电话、金额、ID) -
BeautifulSoup适合基于 DOM 结构定位,再用.get_text()+ 小段正则收尾 - 混合用法最实用:用 BS 定位到父容器,
elem.get_text()后用re.search(r'评分:(\d\.\d)', txt)提取具体值
真正难的不是写出能跑的正则,而是判断什么时候该停手、换工具。HTML 不是文本,它是树——强行扁平化匹配,早晚被某个 <br> 或注释打脸。











