如何用BeautifulSoup解析TEI-XML提取<p><said>内容生成CONLL格式
实现方案
你可以通过遍历<p>标签下的所有子节点(按原始文档顺序保留普通文本节点和<said>标签节点),分别处理不同范围的文本标注,完整可运行代码如下:
from bs4 import BeautifulSoup, NavigableString content = [] # 读取XML文件,指定编码避免乱码 with open("speakers/ABookofGhostsbySSabineBaringGould36638.xml", "r", encoding="utf-8") as file: content = file.read() # 处理XML文件建议用xml解析器,需提前安装lxml库 bs_content = BeautifulSoup(content, "xml") all_txt = [] for result in bs_content.find_all("p"): said = result.find('said') if said == None: conll = [f"{token}\t0" for token in result.get_text().split()] all_txt.append(conll) else: conll = [] # 按原始顺序遍历p标签下的所有直接子节点 for child in result.contents: # 处理未被said标签包裹的普通文本节点 if isinstance(child, NavigableString): text = child.strip() if not text: continue tokens = text.split() conll.extend([f"{token}\t0" for token in tokens]) # 处理said标签节点 elif child.name == "said": said_text = child.get_text().strip() if not said_text: continue said_tokens = said_text.split() # 第一个token标注B-said conll.append(f"{said_tokens[0]}\tB-said") # 剩余token标注I-said if len(said_tokens) > 1: conll.extend([f"{token}\tI-said" for token in said_tokens[1:]]) all_txt.append(conll) # 可选:直接输出为符合规范的CONLL格式文件,段落间空行分隔 with open("output.conll", "w", encoding="utf-8") as f: for para_lines in all_txt: f.write("\n".join(para_lines) + "\n\n")
逻辑说明
- 遍历
<p>标签的.contents属性可以完整保留文档的原始结构顺序,不会混淆标签内外的文本范围 - 支持单个
<p>标签内嵌套多个<said>标签的场景 - 如果你的场景中
<said>是<p>的深层嵌套子节点而非直接子节点,把遍历result.contents的逻辑替换为递归遍历所有后代节点即可适配。
内容的提问来源于stack exchange,提问作者Davide GmailJob
相关产品推荐
相关产品推荐

