使用Python3 BeautifulSoup提取XML中d:BANFN遇nth_child_of_type错误求助
解决BeautifulSoup提取XML命名空间标签时的
nth_child_of_type错误 嘿,这个问题我之前踩过坑!你碰到的nth_child_of_type错误,其实是因为CSS选择器的语法和XML命名空间前缀冲突导致的——当你写soup.select('d:BANFN')时,BeautifulSoup会把冒号后面的BANFN当成CSS伪类(比如:nth-child这种),但这根本不是有效的伪类,所以直接报错了。咱们来一步步解决:
方案一:用命名空间URL精准查找
你的XML里d:是命名空间前缀,对应的完整命名空间URL是http://schemas.microsoft.com/ado/2007/08/dataservices(从<category>标签的scheme属性能看出来)。BeautifulSoup支持用{命名空间URL}标签名的格式来查找带命名空间的标签,代码示例如下:
from bs4 import BeautifulSoup # 你的XML内容 xml_data = """<?xml version="1.0" encoding="utf-8"?> <entry> <title type="text">MATERIALSET('R100100100')</title> <updated>2018-05-11T04:28:47Z</updated> <category term="ZPOC_BOT_PUR_GRP_SRV.MATERIAL" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> <link href="MATERIALSET('R100100100')" rel="self" title="MATERIAL"/> <content type="application/xml"> <m:properties> <d:MATNR>R100100100</d:MATNR> <d:WERKS>Z100</d:WERKS> <d:MENGE> 1.000</d:MENGE> <d:EEIND>29.06.2018</d:EEIND> <d:BANFN>5000000041</d:BANFN> </m:properties> </content> </entry>""" # 用lxml-xml解析器处理XML(比默认解析器更适合XML场景) soup = BeautifulSoup(xml_data, 'lxml-xml') # 指定d前缀对应的命名空间URL d_namespace = 'http://schemas.microsoft.com/ado/2007/08/dataservices' banfn_tag = soup.find(f'{{{d_namespace}}}BANFN') # 提取并打印结果 if banfn_tag: banfn_value = banfn_tag.get_text(strip=True) print(f"提取到的BANFN值:{banfn_value}") else: print("未找到BANFN节点")
方案二:用属性选择器绕过命名空间冲突
如果你不想手动写命名空间URL,也可以用CSS属性选择器匹配完整的标签名(避开冒号被当成伪类的问题),代码更简洁:
# 用select_one匹配name属性为d:BANFN的标签 banfn_tag = soup.select_one('[name="d:BANFN"]') if banfn_tag: banfn_value = banfn_tag.get_text(strip=True) print(f"提取到的BANFN值:{banfn_value}")
进阶优化:缩小查找范围
为了避免匹配到其他位置的同名标签,你可以先定位到<m:properties>节点,再在里面查找BANFN:
# 先找到m:properties节点(m对应的命名空间是metadata的URL) m_namespace = 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' properties_tag = soup.find(f'{{{m_namespace}}}properties') if properties_tag: banfn_tag = properties_tag.find(f'{{{d_namespace}}}BANFN') # 或者用select_one:banfn_tag = properties_tag.select_one('[name="d:BANFN"]') if banfn_tag: print(banfn_tag.get_text(strip=True))
内容的提问来源于stack exchange,提问作者Sarthak Mahapatra
相关产品推荐
相关产品推荐

