Ignore encoding errors in Python (iterparse)?

邮差的信 提交于 2019-11-30 23:59:37

You say:

The character that causes the problem is: å,

How do you know that? What are you viewing your text with?

So you can't publish the URL and your API key; what about reading the data, writing it to a file (in binary mode), and publishing that?

When you open that file in your web browser, what encoding does it detect?

At the very least, do this

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

This will produce an exception that will tell you the byte offset of the non-UTF-8 stuff.

Then do this:

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

and show us the results.

Assuming the encoding is actually cp1252 and decoding the bytes in the lxml error message:

>>> 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']
>>>

So are you seeing e-circumflex followed by ves, or a-ring followed by ves, or a-ring followed by something else?

Does the data start with an XML declaration like <?xml version="1.0" encoding="UTF-8"?>? If not, what does it start with?

Clues for encoding guessing/confirmation: What language is the text written in? What country?

UPDATE based on further information supplied.

Based on the snippet that you showed in the vicinity of the error, the movie title is "La science des rêves" (the science of dreams).

Funny how PHP gags on "F***ing Åmål" but Python chokes on French dreams. Are you sure that you did the same query?

You should have told us it was IMDB up front, you would have got your answer much sooner.

SOLUTION before you pass data to the lxml parser, do this:

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

That's based on the encoding that they declare on their website, but that may be a lie too. In that case, try cp1252 instead. It's definitely not iso-8859-2.

However, the data is not encoded properly, and I am not the provider of it, so I can't fix the encoding.

It is encoded somehow. Determine the encoding, and specify that encoding, instead of UTF-8 encoding (since that is obviously not the encoding).

Iterparse allows you to override xml encodings in the document using its keyword-argument "encoding" (see https://lxml.de/api/lxml.etree.iterparse-class.html). In your code above, you could also write

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

to deal with all european characters in the file.

You can use encode with 'replace' - >>> unicode('\x80abc', errors='replace') this way the bad character is replaced with a valid one - u'\ufffdabc'

To recover from errors during parsing you could use recover option (some data might be ignored in this case):

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

To override the document encoding you could use:

parser=etree.XMLParser(encoding=ENCODING)

Here's how feedparser detects character encoding (it is not trivial).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!