使用BeautifulSoup查找含特殊字符的XML元素失败求助
BS4解析Tableau XML时子节点find方法失效的解决办法
问题场景
解析Tableau生成的XML文档时,根节点调用soup.find能定位到目标标签_.fcp.objectmodelencapsulatelegacy.true...object-graph,但在datasource子节点下调用find却返回None,仅能通过遍历子元素的方式匹配到该标签。
目标XML内容
<datasources> <datasource> <_.fcp.ObjectModelEncapsulateLegacy.true...object-graph> <objects> <object caption='table' id='table'> <properties context='extract'> <relation name='Extract' table='[Extract].[Extract]' type='table' /> </properties> </object> </objects> </_.fcp.ObjectModelEncapsulateLegacy.true...object-graph> </datasource> </datasources>
原解析代码
soup = BeautifulSoup(xmlstr, 'lxml') print(soup.find("_.fcp.objectmodelencapsulatelegacy.true...object-graph")) # 可行!打印该对象的标记 datasources = soup.find('datasources').find_all('datasource') for ds in datasources: print(ds['caption']) print(ds['name']) # 可行! result = ds.find("_.fcp.objectmodelencapsulatelegacy.true...object-graph") print(result.name) # 不可行!返回None for tag in ds: if tag.name == "_.fcp.objectmodelencapsulatelegacy.true...object-graph": print(tag.name) # 可行 ^^
问题原因
目标标签名包含特殊字符(.和连续的...),BS4的find方法直接传入这类字符串时,内部解析逻辑对特殊字符的处理出现异常,导致无法在子节点上下文匹配到对应标签。
解决办法
方法一:用Lambda表达式精确匹配标签名
绕过字符串解析的问题,通过lambda函数直接匹配标签名:
soup = BeautifulSoup(xmlstr, 'lxml') datasources = soup.find('datasources').find_all('datasource') for ds in datasources: result = ds.find(lambda tag: tag.name == "_.fcp.objectmodelencapsulatelegacy.true...object-graph") if result: print(result.name) # 正常输出目标标签名
方法二:遍历后代节点筛选
直接遍历datasource的所有后代节点,筛选出目标标签:
soup = BeautifulSoup(xmlstr, 'lxml') datasources = soup.find('datasources').find_all('datasource') for ds in datasources: target_tag = None for tag in ds.descendants: if tag.name == "_.fcp.objectmodelencapsulatelegacy.true...object-graph": target_tag = tag break if target_tag: print(target_tag.name)
方法三:转义特殊字符后用select方法
如果偏好CSS选择器,需转义标签名中的.(CSS中.代表类选择器):
soup = BeautifulSoup(xmlstr, 'lxml') datasources = soup.find('datasources').find_all('datasource') # 转义所有.为\\. escaped_tag = "\\.".join("_.fcp.objectmodelencapsulatelegacy.true...object-graph".split(".")) for ds in datasources: result = ds.select_one(escaped_tag) if result: print(result.name)
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

