最稳方案是用 xml.etree.elementtree 递归提取 node.text 和 node.tail 并清理空白,手动解码实体与 cdata,大文件必用 iterparse() 配合 clear() 防内存溢出。

用 Python 的 xml.etree.ElementTree 提取纯文本最稳
直接丢掉标签、保留换行和段落结构,xml.etree.ElementTree 是标准库里最轻量也最可控的选择。别碰 BeautifulSoup —— 它默认会补全 HTML 语义(比如把 <p></p> 自动闭合),XML 里没这回事,容易错乱;也别用正则硬扒,嵌套标签一多就崩。
关键不是“怎么读”,而是“怎么递归地跳过标签只留文本”。核心逻辑是:对每个节点,先取 node.text,再递归处理子节点,最后拼上 node.tail(这是很多人漏掉的——标签后的文本就存在这里)。
-
node.text:开始标签和第一个子标签之间的文本 -
node.tail:当前标签闭合后、下一个同级标签开始前的文本(常含换行缩进) - 子节点的
text/tail需显式递归,ElementTree 不自动合并
处理换行和空白字符要主动清理
原始 XML 里的换行、缩进、空格都会原样变成 text 或 tail,直接拼接会导致 TXT 里一堆空行或缩进错乱。不能依赖 strip() 全局处理——那会吃掉段落间必要的空行。
推荐策略:对每段 text 和 tail 单独做 .replace('\n', ' ').replace('\t', ' ').strip(),再按需加换行符。如果源 XML 用 <para></para> 或 <p></p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/code/11106" title="逍遥内容管理系统(Carefree CMS)1.3.0"><img
src="https://img.php.cn/upload/webcode/000/000/019/176498820779736.png" alt="逍遥内容管理系统(Carefree CMS)1.3.0" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/code/11106" title="逍遥内容管理系统(Carefree CMS)1.3.0">逍遥内容管理系统(Carefree CMS)1.3.0</a>
<p>系统简介逍遥内容管理系统(CarefreeCMS)是一款功能强大、易于使用的内容管理平台,采用前后端分离架构,支持静态页面生成,适用于个人博客、企业网站、新闻媒体等各类内容发布场景。核心特性1、模板套装系统 - 支持多套模板自由切换,快速定制网站风格2、静态页面生成 - 一键生成纯静态HTML页面,访问速度快,SEO友好3、文章管理 - 支持富文本编辑、草稿保存、文章属性标记、自动提取SEO4、全</p>
</div>
<a href="/xiazai/code/11106" title="逍遥内容管理系统(Carefree CMS)1.3.0" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div> 包段落,就在进入这类标签时额外追加一个 \n。
- 别用
str(node)或etree.tostring()—— 返回的是带标签的字节流 -
node.tail经常为空字符串或只含空白,检查if node.tail and node.tail.strip()再处理 - 如果 XML 声明了
xml:space="preserve",得改用更谨慎的空白处理逻辑
遇到 CDATA 或实体编码要手动解码
里的内容不会被 ElementTree 自动解析为文本节点,而是整个当做一个 node.text 字符串;而 、< 这类实体也不会被自动转义。结果就是 TXT 里出现裸的 或一堆 <code>。
解决方法分两步:先用 html.unescape() 解实体(Python 3.4+),再对 node.text 做正则提取 CDATA 内容:re.search(r'', text, re.DOTALL)。注意 re.DOTALL 必须加,否则跨行 CDATA 拿不到。
-
html.unescape()能处理"、'、数字字符引用等,但不处理 CDATA - CDATA 提取后要替换原
text,不是追加——否则重复出现 - 某些 XML 用
<script><![CDATA[...]]></script>,这种嵌套结构正则可能失效,得改用 SAX 或 lxml
大文件要用 iterparse() 防内存炸掉
读几百 KB 的 XML 用 ET.parse() 没问题;但一旦超 10MB,DOM 全加载进内存,Python 进程可能直接被系统 kill。这时候必须切到流式解析:ET.iterparse() 边读边清空已处理节点。
重点不是“怎么解析”,而是“什么时候调 root.clear()”。必须在处理完一个完整业务单元(比如一个 <article></article>)后立刻清空其子节点,否则内存只增不减。别等循环结束——那时候早爆了。
-
iterparse()返回 (event, node),只在event == 'end'且node.tag == 'article'时才提取文本并调node.clear() - 别忘了在循环外手动调一次
root.clear(),清掉根节点残留引用 -
iterparse()不自动处理命名空间,如果 XML 有xmlns,得提前传namespaces参数或用通配符*}
text/tail、空白清理要分层、CDATA 和实体得手动拆、大文件必须流式清内存。最容易卡住的是 tail 被忽略,和 iterparse() 忘记 clear()。









