必须指定 features="lxml-xml" 解析 xml,否则静默降级为 html 解析,导致自闭合标签展开、命名空间丢失、大小写被强制转换;带命名空间需用 namespace 参数传字典,标签名大小写敏感。

用 BeautifulSoup 解析 XML 必须指定解析器,否则会静默降级为 HTML 解析
默认不传 features 参数时,BeautifulSoup 会按 HTML 规则解析 XML,导致自闭合标签(如 <item></item>)被错误展开、命名空间丢失、属性大小写被强制转小写。这不是报错,是“看起来能跑,结果不对”。
- 必须显式传
features="xml"或features="lxml-xml"(推荐后者,依赖lxml) - 如果只装了
beautifulsoup4没装lxml,features="xml"会 fallback 到内置html.parser,依然出错——得先pip install lxml -
features="lxml"≠features="lxml-xml":前者仍是 HTML 模式,后者才是真 XML 模式
find() 和 find_all() 在 XML 中对标签名大小写敏感
XML 区分大小写,<item></item> 和 <item></item> 是两个不同标签。而默认 HTML 解析器会把所有标签转成小写再匹配,造成“明明写了 find("Item") 却找不到”。
- 确保标签名拼写、大小写与原始 XML 完全一致
- 用
find_all(True)可列出所有顶层标签名,快速核对实际命名(比如发现其实是<catalogitem></catalogitem>而非<item></item>) - 若需忽略大小写,改用正则:
soup.find_all(re.compile(r"^item$", re.I)),但会损失性能,且不推荐用于结构明确的 XML
带命名空间的 XML 标签必须用字典传入 find() 的 namespace 参数
像 <rss xmlns="http://purl.org/rss/1.0/"></rss> 这种声明后,<channel></channel> 实际属于该命名空间,直接 find("channel") 找不到。
- 不能用
"{http://purl.org/rss/1.0/}channel"这种字符串硬写——BS4 不支持这种前缀语法 - 正确做法:定义命名空间字典,如
ns = {"rss": "http://purl.org/rss/1.0/"},再调用soup.find("channel", namespace=ns) - 如果根节点有默认命名空间(无前缀),需用
ns = {"": "http://purl.org/rss/1.0/"},空字符串键表示默认 ns - 省略
namespace参数 = 完全不匹配任何带 ns 的标签,不是“忽略 ns”
提取文本内容时,.text 会合并所有子文本并抹掉换行缩进,.get_text() 更可控
XML 常含格式化空白(如换行、缩进),.text 把它们全压成单个空格,可能破坏地址、诗歌、代码片段等语义。
-
.get_text(strip=True)默认行为同.text;加strip=False可保留原始换行 - 需要清理多余空白但保留段落结构?用
.get_text(separator="\n", strip=True) - 若标签内混有注释或 CDATA,
.text会跳过它们,.get_text()同样跳过——BS4 不解析 CDATA 内容,得手动取.contents并过滤Comment类型
features 写对、namespace 传对,剩下的就是标签名和文本提取的细节问题。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










