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

3 投票
5 回答
9772 浏览
提问于 2025-04-17 12:51

我已经为这个问题纠结了一个小时了。我正在用 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 中尝试解析时发生的情况。为了澄清一下,F***ing Åmål 是一部剧情电影 =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

Iterparse 这个功能可以让你在处理文档时,使用一个叫“encoding”的参数来覆盖 XML 文件中的编码方式(详细信息可以查看 这个链接)。在你上面的代码中,你也可以这样写

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

这样可以处理文件中的所有欧洲字符。

0

不过,这些数据的编码不太正确,而我并不是提供这些数据的人,所以我无法修复编码问题。

这些数据是以某种方式编码的。你需要找出具体的编码方式,并指定这种编码,而不是使用UTF-8编码(因为显然这不是正确的编码方式)。

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抑扬符的ves,还是带有a抑扬符的ves,或者是带有a抑扬符的其他东西?

数据是否以类似<?xml version="1.0" encoding="UTF-8"?>的XML声明开始?如果不是,那它是以什么开始的?

猜测/确认编码的线索:文本是用什么语言写的?哪个国家的?

更新,基于提供的进一步信息。

根据你在错误附近展示的代码片段,电影标题是"La science des rêves"(梦的科学)。

有趣的是,PHP在处理"F***ing Åmål"时出错,但Python却在处理法语梦时卡住。你确定你做的是同样的查询吗?

你应该一开始就告诉我们是IMDB,这样你会更快得到答案。

解决方案:在你将data传递给lxml解析器之前,先做这个:

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

这是基于他们网站上声明的编码,但这也可能是假的。在这种情况下,试试cp1252。它绝对不是iso-8859-2

撰写回答