解析XML文件获取UnicodeEncodeError(ElementTree)/ ValueError(lxml)

Bio*_*eek 5 python xml lxml elementtree python-requests

我向CareerBuilder API发送GET请求:

import requests

url = "http://api.careerbuilder.com/v1/jobsearch"
payload = {'DeveloperKey': 'MY_DEVLOPER_KEY',
           'JobTitle': 'Biologist'}
r = requests.get(url, params=payload)
xml = r.text
Run Code Online (Sandbox Code Playgroud)

并获得一个看起来像这样的XML .但是,我无法解析它.

使用其中之一 lxml

>>> from lxml import etree
>>> print etree.fromstring(xml)

Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    print etree.fromstring(xml)
  File "lxml.etree.pyx", line 2992, in lxml.etree.fromstring (src\lxml\lxml.etree.c:62311)
  File "parser.pxi", line 1585, in lxml.etree._parseMemoryDocument (src\lxml\lxml.etree.c:91625)
ValueError: Unicode strings with encoding declaration are not supported.
Run Code Online (Sandbox Code Playgroud)

要么 ElementTree:

Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    print ET.fromstring(xml)
  File "C:\Python27\lib\xml\etree\ElementTree.py", line 1301, in XML
    parser.feed(text)
  File "C:\Python27\lib\xml\etree\ElementTree.py", line 1641, in feed
    self._parser.Parse(data, 0)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 3717: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

因此,即使XML文件以

<?xml version="1.0" encoding="UTF-8"?>
Run Code Online (Sandbox Code Playgroud)

我的印象是它包含不允许的字符.如何使用lxml或解析此文件ElementTree

Mar*_*ers 15

您正在使用解码的 unicode值.使用r.raw原始响应数据:

r = requests.get(url, params=payload, stream=True)
r.raw.decode_content = True
etree.parse(r.raw)
Run Code Online (Sandbox Code Playgroud)

它将直接从响应中读取数据; 请注意stream=True选项.get().

设置r.raw.decode_content = True标志可确保原始套接字将为您提供解压缩的内容,即使响应是gzip或deflate压缩也是如此.

你不具备以流的响应; 对于较小的XML文档,可以使用该response.content属性,即未解码的响应主体:

r = requests.get(url, params=payload)
xml = etree.fromstring(r.content)
Run Code Online (Sandbox Code Playgroud)

XML解析器总是期望字节作为输入,因为XML格式本身决定了解析器如何将这些字节解码为Unicode文本.


tut*_*uju 5

更正!

看下面我怎么弄错了.基本上,当我们使用该方法时.text,结果是一个unicode编码的字符串.使用它会在lxml中引发以下异常

ValueError:不支持带编码声明的Unicode字符串.请使用字节输入或XML片段而不声明.

这基本上意味着@ martijn-pieters是对的,我们必须使用返回的原始响应 .content

答案不正确(但可能对某人有趣)

对于谁有兴趣.我相信发生此错误的原因可能是请求的无效猜测,如Response.text文档中所述:

响应的内容,以unicode为单位.

如果Response.encoding为None,则使用chardet猜测编码.

响应内容的编码仅基于HTTP标头确定,遵循RFC 2616到字母.如果您可以利用非HTTP知识来更好地猜测编码,则应在访问此属性之前适当地设置r.encoding.

因此,在此之后,还可以确保请求r.text通过显式设置编码来正确编码响应内容r.encoding = 'UTF-8'

这种方法增加了另一个验证,即在使用lxml解析之前,接收到的响应确实处于正确的编码中.