如何使用Python 3.8的xml.etree模块解析HTML文件?
基于Python标准库xml.etree解析HTML的实现方案
问题根因
你遇到的undefined entity报错是因为默认xml.etree.ElementTree调用parse方法时使用XML解析器,仅预定义了<、>、&、'、"5个实体,无法识别HTML特有的实体(比如 、©等),同时XML解析器对HTML的松散语法(比如未闭合标签)容错性极低。
标准库实现方案
无需引入第三方lxml包,也不用切换到html包,你可以将标准库html.parser.HTMLParser和xml.etree.TreeBuilder结合,生成完全兼容xml.etreeAPI的节点树,具体实现代码如下:
import xml.etree.ElementTree as etree from html.parser import HTMLParser from html.entities import name2codepoint class HTMLElementTreeParser(HTMLParser): def __init__(self): super().__init__() # 初始化ElementTree的树构建器 self.tree_builder = etree.TreeBuilder() def handle_starttag(self, tag, attrs): # 处理标签开始,属性转成字典格式传入构建器 self.tree_builder.start(tag, dict(attrs)) def handle_endtag(self, tag): # 处理标签结束 self.tree_builder.end(tag) def handle_data(self, text): # 处理标签内文本 self.tree_builder.data(text) def handle_entityref(self, name): # 处理HTML实体,转成对应字符传入构建器,解决实体未定义报错 if name in name2codepoint: self.tree_builder.data(chr(name2codepoint[name])) def get_root(self): # 解析完成后返回ElementTree根节点 return self.tree_builder.close() # 调用示例 if __name__ == "__main__": filepathname = "你的HTML文件路径" with open(filepathname, "r", encoding="utf-8") as f: html_content = f.read() parser = HTMLElementTreeParser() parser.feed(html_content) html_root = parser.get_root() # 后续可以正常使用xml.etree的所有API操作节点树,比如: # 遍历所有p标签 for p_node in html_root.iter("p"): print(p_node.text) # 用xpath语法查找节点 all_a_nodes = html_root.findall(".//a")
方案优势
- 完全基于Python标准库实现,无需额外安装依赖,满足即开即用的需求
- 生成的根节点是标准的
Element对象,你之前熟悉的xml.etree所有遍历、查询方法都可以直接使用 - 自动兼容所有HTML预定义实体,不会再抛出实体未定义的异常
内容的提问来源于stack exchange,提问作者Jonathan Sachs
相关产品推荐
相关产品推荐

