XML文件如何通过HTTP GET获取 Python requests下载XML

2次阅读

推荐用 ET.fromstring(r.content) 直接解析 bytes,它自动识别 XML 声明中的 encoding;若声明缺失或冲突,需手动 decode;大文件用 iterparse 流式处理。

XML 文件如何通过 HTTP GET 获取 Python requests 下载 XML

requests.get() 直接获取 XML 内容没问题,但响应体默认是 bytes

Python requests 发起 GET 请求拿到 XML,本质和拿 HTML、JSON 没区别——response.content 是原始字节流,response.text 是解码后的字符串。很多人卡在第一步:用 response.text 解析时报编码错误,比如 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff

  • XML 声明里常带编码(如 <?xml version="1.0" encoding="GBK"?>),但 requests 不会自动按这个解码,它只看 HTTP Content-Type 头里的 charset
  • 如果服务端没返回 charsetresponse.text 默认用 utf-8 解码,而实际是 GB2312ISO-8859-1,就直接崩
  • 稳妥做法是先用 response.content 拿 bytes,再手动按 XML 声明或业务约定解码;或者交给 xml.etree.ElementTree 自己处理(它能识别声明)

用 xml.etree.ElementTree.fromstring() 解析 raw bytes 最省心

别先 decode 再 parse,直接把 response.content 丢给 ET.fromstring() —— 它内部会自动检测 XML 声明里的 encoding 属性,并正确解码。这是最常见也最不容易翻车的方式。

  • ET.fromstring(response.content) 支持 UTF-8、UTF-16、GBK 等主流编码,只要 XML 声明写对了就能认出来
  • 如果 XML 没声明 encoding(不规范但存在),且内容含非 ASCII 字符,fromstring() 可能抛 ParseError;此时得先猜编码,用 response.content.decode('gbk') 得到字符串再传入
  • 注意:不要用 ET.parse() 直接传 URL,它不支持网络路径,只能读本地文件或 file-like object
import requests import xml.etree.ElementTree as ET <p>r = requests.get('<a href="https://www.php.cn/link/73693853a57a48e11cdea2a77e88a501">https://www.php.cn/link/73693853a57a48e11cdea2a77e88a501</a>') r.raise_for_status()  # 别忘了检查 HTTP 状态码 root = ET.fromstring(r.content)  # ✅ 推荐:bytes 直接喂给 fromstring

遇到乱码或解析失败,优先检查 Content-Type 和 XML 声明是否冲突

服务器返回的 Content-Type 头(如 text/xml; charset=ISO-8859-1)和 XML 文件开头的 encoding 声明(如 encoding="UTF-8")打架,是 XML 解析出问题的头号原因。

  • print(r.headers.get('content-type'))print(r.content[:100]) 快速确认两者是否一致
  • 若不一致,以 XML 声明为准(它是 XML 规范强制要求的),忽略 Content-Type 里的 charset
  • 某些老旧系统返回 Content-Type: text/xml 却不带 charset,还用 GBK 编码——这时候必须手动 decode:r.content.decode('gbk')

大 XML 文件别用 .content 全部加载进内存

如果 XML 超过几 MB,response.content 会一次性把整个响应体读进内存,容易 OOM。这时得用流式解析,比如 xml.etree.ElementTree.iterparse() 配合 response.raw

立即学习 Python 免费学习笔记(深入)”;

  • response.raw 是未解码的 socket 流,需设 stream=True 才可用:requests.get(url, stream=True)
  • iterparse() 边读边解析,适合处理 <item> 这类重复子节点,不用一次性载入整棵树
  • 记得调用 response.raw.close() 或用 with requests.get(……, stream=True) as r: 确保连接释放
r = requests.get('https://example.com/big.xml', stream=True) r.raise_for_status() for event, elem in ET.iterparse(r.raw, events=('start', 'end')):     if event == 'end' and elem.tag == 'record':         print(elem.find('title').text)         elem.clear()  # ⚠️ 关键:清空已处理节点,防内存堆积 

XML 的坑不在“怎么下”,而在“怎么不崩”。真正麻烦的永远是编码混乱、声明缺失、服务端瞎配 Content-Type——这些没法靠换库解决,得一层层 inspect 响应头和原始字节。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-22发表,共计2225字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources