Преобразование Юникода в ASCII без ошибок в Python
мой код просто очищает веб-страницу, а затем преобразует ее в Юникод.
html = urllib.urlopen(link).read()
html.encode("utf8","ignore")
self.response.out.write(html)
но я получаю UnicodeDecodeError:
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 507, in __call__
handler.get(*groups)
File "/Users/greg/clounce/main.py", line 55, in get
html.encode("utf8","ignore")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)
Я предполагаю, что это означает, что HTML содержит какую-то неправильно сформированную попытку Unicode где-то. могу ли я просто удалить все байты кода, вызывающие проблему, вместо получения ошибки?
11 ответов:
обновить 2018:
по состоянию на февраль 2018 года, используя сжатия, как
gzipстало довольно популярны (около 73% всех веб-сайтов используют его, включая крупные сайты, такие как Google, YouTube, Yahoo, Wikipedia, Reddit, Stack Overflow и сетевые сайты Stack Exchange).
Если вы сделаете простое декодирование, как в исходном ответе с ответом gzipped, вы получите сообщение об ошибке, подобное или подобное этому:UnicodeDecodeError: кодек 'utf8' не может декодировать байт 0x8b в позиции 1: неожиданный код байт
для декодирования ответа gzpipped вам необходимо добавить следующие модули (в Python 3):
import gzip import ioПримечание:в Python 2 вы используете
StringIOвместоioзатем вы можете разобрать содержимое следующим образом:
response = urlopen("https://example.com/gzipped-ressource") buffer = io.BytesIO(response.read()) # Use StringIO.StringIO(response.read()) in Python 2 gzipped_file = gzip.GzipFile(fileobj=buffer) decoded = gzipped_file.read() content = decoded.decode("utf-8") # Replace utf-8 with the source encoding of your requested resourceэтот код считывает ответ и помещает байты в буфер. Элемент
gzipмодуль затем считывает буфер используя
>>> u'aあä'.encode('ascii', 'ignore') 'a'EDIT:
Декодируйте строку, которую вы возвращаете, используя либо кодировку в соответствующем
metaтег в ответе или вContent-Typeзаголовок, потом кодировать.метод
encode()принимает другие значения как "игнорировать". Например: 'replace', 'xmlcharrefreplace', 'backslashreplace'. Смотрите https://docs.python.org/3/library/stdtypes.html#str.encode
как продолжение ответа Игнасио Васкеса-Абрамса
>>> u'aあä'.encode('ascii', 'ignore') 'a'иногда желательно удалить акценты из символов и распечатать базовую форму. Это можно сделать с помощью
>>> import unicodedata >>> unicodedata.normalize('NFKD', u'aあä').encode('ascii', 'ignore') 'aa'вы также можете перевести другие символы (например, знаки препинания) в их ближайшие эквиваленты, например, правильный символ юникода в одинарных кавычках не преобразуется в ascii-Апостроф при кодировании.
>>> print u'\u2019' ’ >>> unicodedata.name(u'\u2019') 'RIGHT SINGLE QUOTATION MARK' >>> u'\u2019'.encode('ascii', 'ignore') '' # Note we get an empty string back >>> u'\u2019'.replace(u'\u2019', u'\'').encode('ascii', 'ignore') "'"хотя есть более эффективные способы достижения этой цели. Смотрите этот вопрос для более подробной информации где находится "лучший ASCII для этой базы данных Unicode" Python?
использовать unidecode - он даже мгновенно преобразует странные символы в ascii и даже преобразует китайский язык в фонетический ascii.
$ pip install unidecodeзатем:
>>> from unidecode import unidecode >>> unidecode(u'北京') 'Bei Jing' >>> unidecode(u'Škoda') 'Skoda'
Я использую эту вспомогательную функцию во всех моих проектах. Если он не может преобразовать unicode, он игнорирует его. Это связано с библиотекой django, но с небольшим исследованием вы можете обойти ее.
from django.utils import encoding def convert_unicode_to_string(x): """ >>> convert_unicode_to_string(u'ni\xf1era') 'niera' """ return encoding.smart_str(x, encoding='ascii', errors='ignore')Я больше не получаю никаких ошибок unicode после использования этого.
для сломанных консолей, таких как
cmd.exeи вывод HTML вы всегда можете использовать:my_unicode_string.encode('ascii','xmlcharrefreplace')это сохранит все символы, отличные от ascii, делая их печатными в чистом ASCII и в HTML.
предупреждение:если вы используете это в рабочем коде, чтобы избежать ошибок, то скорее всего что-то неправильно в коде. Единственным допустимым вариантом использования для этого является печать на консоли, отличной от unicode, или простое преобразование в HTML-объекты контекст HTML.
и, наконец, если вы находитесь в windows и используете cmd.exe, то вы можете ввести
chcp 65001для включения вывода utf-8 (работает с консольным шрифтом Lucida). Возможно, вам придется добавитьmyUnicodeString.encode('utf8').
вы написали "" " Я предполагаю, что HTML содержит некоторые неправильно сформированные попытки unicode где-то."""
HTML не должен содержать никаких "попыток unicode", хорошо сформированных или нет. Он должен обязательно содержать символы Unicode, закодированные в некоторой кодировке, которая обычно поставляется спереди ... ищите "кодировку".
вы, кажется, предполагаете, что кодировка UTF-8 ... на каком основании? Байт" \xA0", который отображается в сообщении об ошибке указывает, что у вас может быть однобайтовая кодировка, например cp1252.
Если вы не можете получить никакого смысла из объявления в начале HTML, попробуйте использовать chardet чтобы узнать, что такое вероятная кодировка.
почему вы отметили свой вопрос "регулярным выражением"?
обновление после того, как вы заменили весь ваш вопрос не вопрос:
html = urllib.urlopen(link).read() # html refers to a str object. To get unicode, you need to find out # how it is encoded, and decode it. html.encode("utf8","ignore") # problem 1: will fail because html is a str object; # encode works on unicode objects so Python tries to decode it using # 'ascii' and fails # problem 2: even if it worked, the result will be ignored; it doesn't # update html in situ, it returns a function result. # problem 3: "ignore" with UTF-n: any valid unicode object # should be encodable in UTF-n; error implies end of the world, # don't try to ignore it. Don't just whack in "ignore" willy-nilly, # put it in only with a comment explaining your very cogent reasons for doing so. # "ignore" with most other encodings: error implies that you are mistaken # in your choice of encoding -- same advice as for UTF-n :-) # "ignore" with decode latin1 aka iso-8859-1: error implies end of the world. # Irrespective of error or not, you are probably mistaken # (needing e.g. cp1252 or even cp850 instead) ;-)
если у вас есть строка
lineможно использовать.encode([encoding], [errors='strict'])метод для строк для преобразования типов кодирования.
line = 'my big string'
line.encode('ascii', 'ignore')для получения дополнительной информации об обработке ASCII и unicode в Python, это действительно полезный сайт:https://docs.python.org/2/howto/unicode.html
Я думаю, что ответ есть, но только в битах и кусках, что затрудняет быстрое решение проблемы, такой как
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)давайте возьмем пример, Предположим, что у меня есть файл, который имеет некоторые данные в следующем виде (содержащий символы ascii и не ascii )
1/10/17, 21:36 - земле : добро пожаловать ��
и мы хотим игнорировать и сохранять только символы ascii.
этот код будет делать:
import unicodedata fp = open(<FILENAME>) for line in fp: rline = line.strip() rline = unicode(rline, "utf-8") rline = unicodedata.normalize('NFKD', rline).encode('ascii','ignore') if len(rline) != 0: print rlineи тип (rline) будет дать вам
>type(rline) <type 'str'>
unicodestring = '\xa0' decoded_str = unicodestring.decode("windows-1252") encoded_str = decoded_str.encode('ascii', 'ignore')для меня
Похоже, вы используете python 2.икс. Python 2.x по умолчанию для ascii, и он не знает о Unicode. Отсюда и исключение.
просто вставьте нижнюю строку после shebang, это будет работать
# -*- coding: utf-8 -*-
Comments