使用xmltodict解析XML报ExpatError无效令牌错误该如何解决?
问题触发原因
- 编码识别错误:你调用
requests.Response.text时,requests会自动根据响应头猜测内容编码,对欧洲站点的XML文件猜测准确率很低,解码后会生成乱码式的非法字符,expat解析器无法识别。 - XML内容存在非法内容:包括未转义的XML保留字符(
&、<、>等)、XML规范不允许的控制字符、UTF-8 BOM头等,都会触发expat解析报错。 - stream模式的隐性问题:你开启了
stream=True参数但没有按块读取内容,小概率会出现内容截断不完整的情况,也会导致XML非良构。
修复方案
方案1:优先使用二进制内容解析(解决90%以上同类型问题)
xmltodict的parse方法原生支持bytes类型输入,无需手动解码,直接传入响应的二进制内容即可避免编码识别错误,不需要的stream=True参数可直接移除:
import requests import xmltodict metadataxml = "https://nedlasting.geonorge.no/geonorge/Tjenestefeed_daglig.xml" md_response = requests.get(metadataxml) # 直接传入二进制内容,不要用.text属性 xml = xmltodict.parse(md_response.content)
方案2:预处理过滤非法字符(针对内容本身存在非法字符的情况)
如果方案1仍报错,可先过滤掉XML规范不允许的控制字符再解析:
import re import requests import xmltodict # 匹配XML非法控制字符的正则 illegal_xml_re = re.compile(r'[\x00-\x08\x0b-\x0c\x0e-\x1f]') metadataxml = "https://nedlasting.geonorge.no/geonorge/Tjenestefeed_daglig.xml" md_response = requests.get(metadataxml) # 用utf-8-sig解码自动处理BOM头,再过滤非法字符 md_data = illegal_xml_re.sub('', md_response.content.decode('utf-8-sig')) xml = xmltodict.parse(md_data)
方案3:使用容错解析器(针对XML本身存在轻微非良构问题)
如果XML存在未转义保留字符等问题,可替换底层解析器为带容错模式的lxml,不需要修改XML内容即可完成解析,需先安装依赖:pip install lxml
import requests import xmltodict from lxml import etree metadataxml = "https://nedlasting.geonorge.no/geonorge/Tjenestefeed_daglig.xml" md_response = requests.get(metadataxml) # 配置lxml容错解析器 parser = etree.XMLParser(recover=True) xml = xmltodict.parse(md_response.content, parser=parser)
内容的提问来源于stack exchange,提问作者Johs
相关产品推荐
相关产品推荐

