如何用Python按指定非配对HTML标签分割HTML字符串?
如何用Python按指定非配对HTML标签分割HTML字符串?
嘿,我明白你现在的困扰了——你想把一段HTML字符串按照指定的*非配对(自闭合)*标签拆分,比如<br>不管带不带属性、空格多不多,都能准确分割,甚至还考虑了两种输出形式:要么保留原始上下文,要么给每个拆分后的文本段补全父标签。
你之前试了用BeautifulSoup找标签的sourcepos、string这些属性,还有lxml的with_tail=False参数,结果都没拿到想要的标签在原字符串里的起止索引,这其实是因为这类HTML解析库会把原始字符串转换成DOM树结构,丢失了原字符串的精确位置信息,所以靠它们直接拿索引确实走不通,得换两个更可行的思路:
方案一:直接拆分原字符串,保留原始上下文
这个方案用正则表达式精准匹配指定的自闭合标签,直接在原字符串上分割,完美保留原始的HTML结构,对应你要的第一种输出:
import re def split_html_by_unpaired_tag(input_str, tag_name): # 正则匹配规则:匹配指定标签开头,忽略大小写,允许任意属性和空格 tag_pattern = re.compile(f'<{tag_name}\\b[^>]*>', re.IGNORECASE) # 按匹配到的标签分割字符串 raw_parts = tag_pattern.split(input_str) # 过滤空字符串并去除首尾空格(避免标签在开头/结尾产生空项) return [part.strip() for part in raw_parts if part.strip()] # 测试第一个示例 print(split_html_by_unpaired_tag('hello<br >there', 'br')) # 输出: ['hello', 'there'] # 测试第二个示例 test_html = '<div id="d71">text1<br data-i="1">text2<br>text3</div>' print(split_html_by_unpaired_tag(test_html, 'br')) # 输出: ['<div id="d71">text1', 'text2', 'text3</div>']
方案二:拆分后自动补全父标签
如果你想要的是第二种输出(每个文本段都带上父容器标签),那用BeautifulSoup来操作DOM树重构内容会更稳妥,不用手动拼接标签:
from bs4 import BeautifulSoup def split_html_with_parent_wrapper(input_str, split_tag_name): soup = BeautifulSoup(input_str, 'html.parser') result_list = [] # 找到所有要作为分割符的标签 split_tags = soup.find_all(split_tag_name) # 处理第一个文本块:从HTML开头到第一个分割标签前的内容 if split_tags: first_content = soup.contents[0] if first_content and str(first_content).strip(): # 复制父标签的结构和属性 parent_tag = soup.new_tag(first_content.parent.name, **first_content.parent.attrs) parent_tag.append(str(first_content).strip()) result_list.append(str(parent_tag)) # 处理分割标签之间的每个文本块 for tag in split_tags: next_content = tag.next_sibling if next_content and str(next_content).strip(): parent_copy = soup.new_tag(tag.parent.name, **tag.parent.attrs) parent_copy.append(str(next_content).strip()) result_list.append(str(parent_copy)) else: # 如果没有找到分割标签,直接返回原HTML的列表形式 result_list.append(input_str) return result_list # 测试第二个示例 test_html = '<div id="d71">text1<br data-i="1">text2<br>text3</div>' print(split_html_with_parent_wrapper(test_html, 'br')) # 输出: ['<div id="d71">text1</div>', '<div id="d71">text2</div>', '<div id="d71">text3</div>']
这两个方案分别对应你提到的两种输出需求,你可以根据实际场景选其中一个用。
备注:内容来源于stack exchange,提问作者Nils
相关产品推荐
相关产品推荐

