忽略Python中的编码错误(iterparse)?

时间:2012-02-11 18:48:49

标签: python encoding iterparse

我一直在和这个战斗一个小时了。我正在使用iterparse解析XML字符串。但是,数据编码不正确,我不是它的提供者,所以我无法修复编码。

这是我得到的错误:

lxml.etree.XMLSyntaxError: line 8167: Input is not proper UTF-8, indicate encoding !
Bytes: 0xEA 0x76 0x65 0x73

如何才能简单地忽略此错误并继续解析?我不介意,如果一个角色没有妥善保存,我只需要数据。

这是我尝试过的,都是从互联网上挑选的:

data = data.encode('UTF-8','ignore')
data = unicode(data,errors='ignore')
data = unicode(data.strip(codecs.BOM_UTF8), 'utf-8', errors='ignore')

修改
我无法显示网址,因为它是私有API并且涉及我的API密钥,但这是我获取数据的方式:

ur = urlopen(url)
data = ur.read()

导致问题的字符是:å,我猜ä& ö等也会破坏它。

这是我尝试解析它的部分:

def fast_iter(context, func):
    for event, elem in context:
        func(elem)
        elem.clear()
        while elem.getprevious() is not None:
            del elem.getparent()[0]
    del context

def process_element(elem):
    print elem.xpath('title/text( )')

context = etree.iterparse(StringIO(data), tag='item')
fast_iter(context, process_element)

编辑2:
当我尝试在PHP中解析它时,会发生This。只是为了澄清,F ***ingÅmål是drama movie = D

文件以<?xml version="1.0" encoding="UTF-8" ?>

开头

以下是我从print repr(data[offset-10:offset+60])获得的内容:

ence des r\xeaves, La</title>\n\t\t<year>2006</year>\n\t\t<imdb>0354899</imdb>\n

5 个答案:

答案 0 :(得分:3)

你说:

  

导致问题的角色是:å,

你怎么知道的?你在看什么文字?

因此您无法发布网址和API密钥;如何读取数据,将其写入文件(以二进制模式),然后发布?

当您在网络浏览器中打开该文件时,它会检测到哪种编码?

至少,这样做

data.decode('utf8') # where data is what you get from ur.read()

这将产生一个异常,告诉你非UTF-8的字节偏移量。

然后这样做:

print repr(data[offset-10:offset+60])

并向我们展示结果。

假设编码实际上是cp1252并解码lxml错误消息中的字节:

>>> guff = "\xEA\x76\x65\x73"
>>> from unicodedata import name
>>> [name(c) for c in guff.decode('1252')]
['LATIN SMALL LETTER E WITH CIRCUMFLEX', 'LATIN SMALL LETTER V', 'LATIN SMALL LE
TTER E', 'LATIN SMALL LETTER S']
>>>

那么你是否看到e-circumflex后跟ves,或者a-ring后跟ves,或者a-ring后跟别的东西?

数据是否以<?xml version="1.0" encoding="UTF-8"?>之类的XML声明开头?如果没有,它从什么开始?

猜测/确认编码的线索:写入的文字是什么语言?什么国家?

根据提供的更多信息

更新

根据你在错误附近展示的片段,电影标题是“La sciencedesrêves”(梦的科学)。

有趣的是PHP如何对“F ***ingÅmål”嗤之以鼻,但Python对法国梦的扼杀。你确定你做了同样的查询吗?

你应该事先告诉我们它是IMDB,你会更早得到答案。

在将data传递给lxml解析器之前,

解决方案,请执行以下操作:

data = data.replace('encoding="UTF-8"', 'encoding="iso-8859-1"')

这是基于他们在网站上声明的编码,但这也可能是谎言。在这种情况下,请尝试使用cp1252。这肯定是而不是iso-8859-2

答案 1 :(得分:0)

  

但是,数据编码不正确,我不是它的提供者,所以我无法修复编码。

编码以某种方式。确定编码,并指定编码,而不是UTF-8编码(因为这显然不是编码)。

答案 2 :(得分:0)

Iterparse允许您使用其关键字参数“ encoding”覆盖文档中的xml编码(请参见https://lxml.de/api/lxml.etree.iterparse-class.html)。 在上面的代码中,您还可以编写

context = etree.iterparse(StringIO(data), tag='item', encoding='iso-8859-1') 

处理文件中的所有欧洲字符。

答案 3 :(得分:-1)

你可以使用'replace'编码 - >>> unicode('\x80abc', errors='replace') 这样,坏的角色被有效的角色取代 - u'\ufffdabc'

答案 4 :(得分:-1)

要在解析过程中从错误中恢复,可以使用recover选项(在这种情况下可能会忽略某些数据):

import urllib2
from lxml import etree

data = urllib2.urlopen(URL).read()
root = etree.fromstring(data, parser=etree.XMLParser(recover=True))
for item in root.iter('item'):
    # process item here

要覆盖您可以使用的文档编码:

parser=etree.XMLParser(encoding=ENCODING)

这里是feedparser detects character encoding的方式(这不是一件小事)。