Python: конвертировать Unicode в ASCII без ошибок

Мой код просто царапает веб-страницу, а затем преобразует ее в Юникод.

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 Solutions collect form web for “Python: конвертировать Unicode в ASCII без ошибок”

Можем ли мы получить фактическое значение, используемое для link ?

Кроме того, мы обычно сталкиваемся с этой проблемой здесь, когда пытаемся .encode() уже закодированную строку байта. Поэтому вы можете попробовать сначала его декодировать, как в

 html = urllib.urlopen(link).read() unicode_str = html.decode(<source encoding>) encoded_str = unicode_str.encode("utf8") 

В качестве примера:

 html = '\xa0' encoded_str = html.encode("utf8") 

Сбой с

 UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128) 

В то время как:

 html = '\xa0' decoded_str = html.decode("windows-1252") encoded_str = decoded_str.encode("utf8") 

Превосходит ошибки. Обратите внимание, что «windows-1252» – это то, что я использовал в качестве примера . Я получил это от чарта, и у него было 0,5 уверенности, что это правильно! (ну, как указано в строке длиной 1 символа, что вы ожидаете). Вы должны изменить это на кодировку строки байта, возвращаемой из .urlopen().read() к тому, что относится к полученному вами контенту.

Еще одна проблема, я вижу, что метод .encode() string возвращает измененную строку и не изменяет исходный код на месте. Поэтому бесполезно иметь self.response.out.write(html) поскольку html не является кодированной строкой из html.encode (если это то, к чему вы изначально стремились).

Как предложил Игнасио, проверьте исходную веб-страницу для фактического кодирования возвращаемой строки из read() . Это либо в одном из метатегов, либо в заголовке ContentType в ответе. Используйте это как параметр для .decode() .

Однако имейте в виду, что не следует полагать, что другие разработчики достаточно ответственны, чтобы убедиться, что объявления заголовка заголовка и / или метасимвола соответствуют фактическому содержимому. (Это PITA, да, я должен знать, я был одним из тех, кто раньше).

 >>> u'aあä'.encode('ascii', 'ignore') 'a' 

РЕДАКТИРОВАТЬ:

Расшифруйте строку, которую вы вернете, используя либо кодировку в соответствующем meta в ответе, либо в заголовке Content-Type , а затем закодируйте.

Метод encode() принимает другие значения как «игнорировать». Например: «заменить», «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' 

Вы также можете перевести другие символы (например, пунктуацию) в их ближайшие эквиваленты, например символ юникода RIGHT SINGLE QUOTATION MARK не преобразуется в ascii APOSTROPHE при кодировании.

 >>> 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 Python для этой Unicode»?

Используйте unidecode – он даже мгновенно превращает странные персонажи в ascii и даже преображает китайцев в фонетический ascii.

 $ pip install unidecode 

тогда:

 >>> from unidecode import unidecode >>> unidecode(u'北京') 'Bei Jing' >>> unidecode(u'Škoda') 'Skoda' 

Я использую эту вспомогательную функцию во всех своих проектах. Если он не может преобразовать Юникод, он игнорирует его. Это связано с библиотекой 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.

ПРЕДУПРЕЖДЕНИЕ . Если вы используете это в производственном коде, чтобы избежать ошибок, скорее всего, что-то не так в вашем коде . Единственный допустимый прецедент для этого – печать на консоли без юникода или простое преобразование в HTML-объекты в контексте HTML.

И, наконец, если вы находитесь на окнах и используете cmd.exe, тогда вы можете ввести chcp 65001 для включения вывода utf-8 (работает с шрифтом Lucida Console). Возможно, вам потребуется добавить myUnicodeString.encode('utf8') .

Вы написали «» «Я предполагаю, что это означает, что HTML содержит некорректную попытку в unicode где-то». «"

HTML НЕ должен содержать какой-либо «попытки в unicode», хорошо сформированный или нет. Он должен обязательно содержать символы Unicode, закодированные в некотором кодировании, которые обычно поставляются впереди … ищите «charset».

Вы полагаете, что кодировка UTF-8 … на каком основании? Байт «\ xA0», который отображается в вашем сообщении об ошибке, указывает, что у вас может быть однобайтовая кодировка, например, cp1252.

Если вы не можете понять смысл объявления в начале HTML-кода, попробуйте использовать chardet, чтобы узнать, какова вероятная кодировка.

Почему вы отметили свой вопрос с помощью «regex»?

Обновление после того, как вы заменили весь свой вопрос вопросом:

 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 eg 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 и non-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.x. Python 2.x по умолчанию соответствует ascii, и он не знает о Unicode. Отсюда исключение.

Просто вставьте нижнюю строку после shebang, она будет работать

 # -*- coding: utf-8 -*- 
  • python utf-8 japanese
  • Прочтите много файлов csv и запишите их в кодировку utf8 с помощью python
  • Турецкая кодировка символов
  • Python: UnicodeDecodeError: кодек ascii не может декодировать байт 0xef в позиции 0: порядковый номер не в диапазоне (128)
  • Notepad ++ конвертирует в UTF-8 несколько файлов
  • Проблема с кодировкой Python
  • Проблема с кодировкой при загрузке HTML с использованием mechanize и Python 2.6
  • Как преобразовать тему электронной почты из «? UTF-8? ...? =» В читаемую строку?
  • Python - лучший язык программирования в мире.