不使用外部库的Python HTML解析器开发方案咨询
自研HTML解析器+CRUD实现思路
你的现有方案可行性分析
1. 元组列表存储
可行,但仅适用于极简单的扁平HTML结构(比如只有单层无嵌套的标签)。元组的不可变性会导致更新/删除操作必须重新生成整个列表,完全无法表示HTML的嵌套层级关系,CRUD操作会非常繁琐,复杂场景下基本不可用。
2. 字符串拆分标签
可行,但需要处理大量边界情况,维护成本极高。比如要区分注释、自闭合标签、带引号/不带引号的属性、嵌套标签、转义字符等,稍有遗漏就会解析出错;而且拆分后的数据无结构化,CRUD需要手动定位字符串位置,极易引入bug,仅适合快速验证原型。
更优实现方案:自定义DOM类构建层级树
这是最适配HTML结构和CRUD需求的方案,核心是用自定义类封装HTML节点的所有属性,通过树结构表示嵌套关系,操作灵活且易维护。
核心DOM节点类示例
class DOMNode: def __init__(self, tag_name, attributes=None, text_content=''): self.tag_name = tag_name # 标签名,如'div'、'p' self.attributes = attributes or {} # 属性字典,如{'id': 'header', 'class': 'bold'} self.text_content = text_content # 节点内的纯文本内容 self.children = [] # 子节点列表,存储DOMNode实例 def add_child(self, node): self.children.append(node) def remove_child(self, node): if node in self.children: self.children.remove(node)
解析器实现步骤
1. 文件读取与预处理
- 读取HTML文件内容为字符串,先过滤掉注释(
<!-- 注释内容 -->),可以用字符串替换或正则匹配移除。 - 可选:合并连续的空白字符(比如多个换行、空格),但要注意保留文本节点内的必要空白。
2. 词法分析(分词)
遍历字符串,拆分出以下类型的token:
- 开始标签:如
<div class="box">,拆分出标签名div和属性{'class': 'box'} - 结束标签:如
</div>,拆分出标签名div - 自闭合标签:如
<img src="pic.jpg"/>,拆分出标签名img和属性{'src': 'pic.jpg'} - 文本节点:非标签范围内的纯文本内容
3. 语法分析(构建DOM树)
用栈结构处理嵌套关系:
- 遇到开始标签:创建DOMNode实例,压入栈中,作为当前父节点
- 遇到文本节点:将文本内容添加到栈顶节点的
text_content(或作为独立文本节点,视需求而定) - 遇到自闭合标签:创建DOMNode实例,添加到栈顶节点的子节点列表
- 遇到结束标签:弹出栈顶节点,将其添加到新的栈顶节点的子节点列表(栈为空时作为根节点)
CRUD操作实现要点
- 创建(Create):新建DOMNode实例,调用目标父节点的
add_child方法;或在子节点列表的指定位置插入。 - 读取(Read):写递归遍历方法,根据标签名、属性值或层级路径查找节点;比如:
def find_nodes_by_tag(root, tag_name): result = [] if root.tag_name == tag_name: result.append(root) for child in root.children: result.extend(find_nodes_by_tag(child, tag_name)) return result - 更新(Update):直接修改节点的
tag_name、attributes或text_content;或替换子节点。 - 删除(Delete):找到目标节点的父节点,调用
remove_child方法;或清空节点的子节点列表。
关键边界处理
- 自闭合标签:解析时判断标签末尾是否带有
/,无需匹配结束标签 - 属性解析:支持带双引号、单引号或无引号的属性值,比如
class="box"、class='box'、class=box - 转义字符:维护一个转义映射表,将
<转成<、>转成>等
内容的提问来源于stack exchange,提问作者Todor Popov
相关产品推荐
相关产品推荐

