Кодек UnicodeEncodeError: 'в кодировке ASCII' не могу закодировать символ U'xa0' в позиции 20: порядковый номер не в диапазон(128)
у меня возникли проблемы с символами Юникода из текста, извлеченного из разных веб-страниц (на разных сайтах). Я использую BeautifulSoup.
проблема в том, что ошибка не всегда воспроизводима; иногда она работает с некоторыми страницами, а иногда она блевает, бросая UnicodeEncodeError. Я пробовал почти все, что я могу придумать, и все же я не нашел ничего, что работает последовательно, не бросая какую-то ошибку, связанную с Unicode.
один разделы кода, который вызывает проблемы, показано ниже:
agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
вот трассировка стека, созданная на некоторых строках, когда выполняется приведенный выше фрагмент:
Traceback (most recent call last):
File "foobar.py", line 792, in <module>
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'xa0' in position 20: ordinal not in range(128)
Я подозреваю, что это связано с тем, что некоторые страницы (или, более конкретно, страницы с некоторых сайтов) могут быть закодированы, в то время как другие могут быть не закодированы. Все сайты базируются в Великобритании и предоставляют данные, предназначенные для потребления в Великобритании , поэтому нет никаких проблем, связанных с интернализацией или обработкой текста ни на чем, кроме английского.
есть ли у кого-нибудь идеи о том, как решить эту проблему, чтобы я мог последовательно исправить эту проблему?
19 ответов:
вам нужно прочитать Python Unicode HOWTO. Эта ошибка является самый первый пример.
В принципе, прекратите использовать
strдля преобразования из юникода в кодированный текст / байты.вместо этого, правильно использовать
.encode()для кодирования строки:p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()или работать полностью в Unicode.
Это классический python unicode болевой точки! Рассмотрим следующее:
a = u'bats\u00E0' print a => batsàвсе хорошо до сих пор, но если мы назовем str(a), давайте посмотрим, что произойдет:
str(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)о дип, это никому не принесет пользы! Чтобы исправить ошибку, Закодируйте байты явно .кодируйте и скажите python, какой кодек использовать:
a.encode('utf-8') => 'bats\xc3\xa0' print a.encode('utf-8') => batsàвуаля\u00E0!
проблема в том, что при вызове str (), python использует кодировку символов по умолчанию, чтобы попытаться закодировать байты, которые вы ему дали, которые в вашем случае иногда являются представлениями символов Юникода. Чтобы устранить проблему, вы должны сказать python, как обращаться со строкой, которую вы ему даете, используя .encode ('whatever_unicode'). Большую часть времени, вы должны быть в порядке, используя utf-8.
для отличной экспозиции по этой теме см. команда PyCon говорить Нэд Батчелдер здесь: http://nedbatchelder.com/text/unipain.html
Я нашел элегантную работу вокруг меня, чтобы удалить символы и продолжать держать строку как строку в следующем:
yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')важно отметить, что использование параметра игнорировать-это опасно потому что он молча отбрасывает любую поддержку Юникода (и интернационализации) из кода, который его использует, как видно здесь (преобразование Юникода):
>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii') 'City: Malm'
ну я попробовал все, но это не помогло, после того, как погуглил я понял следующее, И это помогло. используется python 2.7.
# encoding=utf8 import sys reload(sys) sys.setdefaultencoding('utf8')
тонкая проблема, вызывающая даже сбой печати, заключается в том, что ваши переменные среды установлены неправильно, например. здесь LC_ALL установлен в "C". В Debian они не рекомендуют устанавливать его: Debian wiki on Locale
$ echo $LANG en_US.utf8 $ echo $LC_ALL C $ python -c "print (u'voil\u00e0')" Traceback (most recent call last): File "<string>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128) $ export LC_ALL='en_US.utf8' $ python -c "print (u'voil\u00e0')" voilà $ unset LC_ALL $ python -c "print (u'voil\u00e0')" voilà
Я на самом деле обнаружил, что в большинстве моих случаев просто удалить эти символы намного проще:
s = mystring.decode('ascii', 'ignore')
для меня, что получилось было:
BeautifulSoup(html_text,from_encoding="utf-8")надеюсь, это кому-то поможет.
добавить строку ниже в начале вашего скрипта ( или как вторую строку):
# -*- coding: utf-8 -*-это определение кодировки исходного кода python. Дополнительная информация в PEP 263.
проблема в том, что вы пытаетесь напечатать символ Юникода, но ваш терминал не поддерживает его.
вы можете попробовать установить
language-pack-enпакета, чтобы исправить это:sudo apt-get install language-pack-enкоторый обеспечивает обновление данных перевода на английский язык для всех поддерживаемых пакетов (включая Python). При необходимости установите другой языковой пакет (в зависимости от того, какие символы вы пытаетесь распечатать).
на некоторых дистрибутивах Linux это необходимо для того, чтобы убедиться, что английский язык по умолчанию настроен правильно (поэтому символы юникода могут обрабатываться оболочкой/терминалом). Иногда это проще установить, чем настроить его вручную.
затем при написании кода, убедитесь, что вы используете правильную кодировку в коде.
например:
open(foo, encoding='utf-8')если у вас все еще есть проблема, дважды проверьте конфигурацию системы, например:
ваш файл локали (
/etc/default/locale), которые должны например,LANG="en_US.UTF-8" LC_ALL="en_US.UTF-8"стоимостью
LANG/LC_CTYPEв Shell.проверьте, какой язык поддерживает ваша оболочка:
locale -a | grep "UTF-8"
демонстрация проблемы и решения в новой виртуальной машине.
инициализировать и подготовить виртуальную машину (например, с помощью
vagrant):vagrant init ubuntu/trusty64; vagrant up; vagrant sshпосмотреть: доступно Ubuntu коробки..
печать символов Юникода (например, знак торговой марки, например
™):$ python -c 'print(u"\u2122");' Traceback (most recent call last): File "<string>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 0: ordinal not in range(128)теперь установка
language-pack-en:$ sudo apt-get -y install language-pack-en The following extra packages will be installed: language-pack-en-base Generating locales... en_GB.UTF-8... /usr/sbin/locale-gen: done Generation complete.теперь проблема решена:
$ python -c 'print(u"\u2122");' ™
вот перефразирование некоторых других так называемых" полицейских " ответов. Есть ситуации, в которых просто выбрасывание проблемных символов/строк является хорошим решением, несмотря на протесты, озвученные здесь.
def safeStr(obj): try: return str(obj) except UnicodeEncodeError: return obj.encode('ascii', 'ignore').decode('ascii') except: return ""тестирование это:
if __name__ == '__main__': print safeStr( 1 ) print safeStr( "test" ) print u'98\xb0' print safeStr( u'98\xb0' )результаты:
1 test 98° 98предложение: вы можете назвать эту функцию ? Это вопрос предпочтения.
простые вспомогательные функции найдены здесь.
def safe_unicode(obj, *args): """ return the unicode representation of obj """ try: return unicode(obj, *args) except UnicodeDecodeError: # obj is byte string ascii_text = str(obj).encode('string_escape') return unicode(ascii_text) def safe_str(obj): """ return the byte string representation of obj """ try: return str(obj) except UnicodeEncodeError: # obj is unicode return unicode(obj).encode('unicode_escape')
Я просто использовал следующее:
import unicodedata message = unicodedata.normalize("NFKD", message)проверьте, что говорит об этом документация:
unicodedata.normalize (form, unistr) возвращает форму нормальной формы для строка Unistr в Юникоде. Допустимые значения для формы: 'NFC',’NFKC', 'NFD‘, и’NFKD'.
стандарт Юникода определяет различные формы нормализации Юникода строка, основанная на определении канонической эквивалентности и эквивалентность совместимости. В Юникоде, несколько характеры могут быть выражается по-разному. Например, символ U + 00C7 (латиница Заглавная буква C с CEDILLA) также может быть выражена в виде последовательности U + 0043 (ЛАТИНСКАЯ ЗАГЛАВНАЯ БУКВА C) U+0327 (СОЧЕТАНИЕ CEDILLA).
для каждого символа существует две нормальные формы: нормальная форма C и нормальная форма D. нормальная форма D (NFD) также известна как каноническая разложение, и переводит каждый символ в его разложенную форму. Нормальная форма C (NFC) сначала применяет канонический разложение, тогда снова создает предварительно объединенные символы.
в дополнение к этим двум формам, есть две дополнительные нормальные формы на основе эквивалентности совместимости. В Юникоде некоторые символы являются поддерживается, который обычно будет объединен с другими символами. Для например, U + 2160 (римская цифра один) на самом деле то же самое, что и U + 0049 (ЛАТИНСКАЯ ЗАГЛАВНАЯ БУКВА I). Однако, он поддерживается в Unicode совместимость с существующими наборами символов (например набор gb2312).
нормальная форма KD (NFKD) будет применять декомпозицию совместимости, т. е. заменить все символы совместимости их эквивалентами. Этот нормальная форма KC (NFKC) сначала применяет декомпозицию совместимости, далее следует каноническая композиция.
даже если две строки Юникода нормализованы и выглядят одинаково для a человек-читатель, если у одного есть комбинирующие символы, а у другого нет, они не могут сравнивать равный.
решает все за меня. Просто и легко.
Я всегда помещаю код ниже в первые две строки файлов python:
# -*- coding: utf-8 -*- from __future__ import unicode_literals
мы поразили эту ошибку при запуске
manage.py migrateв Джанго с локализованными светильниками.наш источник содержит
# -*- coding: utf-8 -*-объявление, MySQL был правильно настроен для utf8 и Ubuntu имел соответствующий языковой пакет и значения в/etc/default/locale.проблема была просто в том, что контейнер Django (мы используем docker) отсутствовал
LANGenv var.задание
LANGдоen_US.UTF-8и перезапуск контейнера перед повторным запуском миграции исправлена проблема.
ниже Решение работает для меня, просто добавил
u "String"
(представляя строку как unicode) перед моей строкой.
result_html = result.to_html(col_space=1, index=False, justify={'right'}) text = u""" <html> <body> <p> Hello all, <br> <br> Here's weekly summary report. Let me know if you have any questions. <br> <br> Data Summary <br> <br> <br> {0} </p> <p>Thanks,</p> <p>Data Team</p> </body></html> """.format(result_html)
У меня просто была эта проблема, и Google привел меня сюда, так что просто добавить к общим решениям здесь, это то, что сработало для меня:
# 'value' contains the problematic data unic = u'' unic += value value = unicУ меня была эта идея после прочтения Нэд!--5-->.
Я не утверждаю, что полностью понимаю, почему это работает, хотя. Поэтому, если кто-то может отредактировать этот ответ или добавить комментарий, чтобы объяснить, я буду признателен.
Если у вас есть что-то вроде
packet_data = "This is data"после этого на следующей строке, сразу после инициализацииpacket_data:unic = u'' packet_data = unic
Comments