UnicodeEncodeError: кодек ascii не может кодировать символ u '\ xa0' в позиции 20: порядковый номер не в диапазоне (128)
У меня проблемы с символами Unicode из текста, полученного с разных веб-страниц (на разных сайтах). Я использую 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)
Я подозреваю, что это связано с тем, что некоторые страницы (или, более конкретно, страницы с некоторых сайтов) могут быть закодированы, в то время как другие могут быть незакодированными. Все сайты базируются в Великобритании и предоставляют данные, предназначенные для потребления в Великобритании, поэтому нет вопросов, связанных с интернализацией или использованием текста, написанного ничем, кроме английского.
Есть ли у кого-нибудь идеи относительно того, как решить эту проблему, чтобы я смог ПОСЛЕДОВАТЕЛЬНО исправить эту проблему?
Ответы
Ответ 1
Вам нужно прочитать Python Unicode HOWTO. Эта ошибка является самым первым примером .
В принципе, прекратите использование str
для преобразования из Юникода в кодированный текст/байты.
Вместо этого используйте .encode()
для кодирования строки:
p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()
или полностью работать в юникоде.
Ответ 2
Это классическая точка болиды unicode python! Рассмотрим следующее:
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)
О, дай, что никому ничего не сделаешь! Чтобы исправить ошибку, закодируйте байты явно с помощью .encode и скажите python, какой кодек использовать:
a.encode('utf-8')
=> 'bats\xc3\xa0'
print a.encode('utf-8')
=> batsà
Voil\u00E0!
Проблема заключается в том, что при вызове str() python использует кодировку символов по умолчанию, чтобы попытаться и закодировать байты, которые вы ей дали, что в вашем случае иногда представляет собой символы юникода. Чтобы устранить проблему, вы должны сказать python, как обращаться со строкой, которую вы даете ей, используя .encode('whatever_unicode'). В большинстве случаев вы должны быть в порядке, используя utf-8.
За отличную экспозицию по этой теме см. Ned Batchelder PyCon здесь: http://nedbatchelder.com/text/unipain.html
Ответ 3
Я нашел изящную работу для меня, чтобы удалить символы и продолжать сохранять строку как строку следующим образом:
yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')
Важно заметить, что использование параметра ignore опасно, поскольку он молча отбрасывает любую поддержку юникода (и интернационализации) из кода, который его использует, как показано здесь (convert unicode):
>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii')
'City: Malm'
Ответ 4
Ну, я пробовал все, но это не помогло, после того, как я разобрался, я понял следующее, и это помогло.
используется python 2.7.
# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
Ответ 5
Тонкая проблема, вызывающая потерю печати даже при неправильной настройке переменных среды, например. здесь LC_ALL установлен на "C". В Debian они препятствуют настройке: Debian wiki в 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à
Ответ 6
Для меня работала:
BeautifulSoup(html_text,from_encoding="utf-8")
Надеюсь, это поможет кому-то.
Ответ 7
Я действительно обнаружил, что в большинстве моих случаев просто удаление этих символов намного проще:
s = mystring.decode('ascii', 'ignore')
Ответ 8
Проблема в том, что вы пытаетесь напечатать символ Юникода, но ваш терминал не поддерживает его.
Вы можете попробовать установить пакет 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"
или:
LC_ALL=C.UTF-8
LANG=C.UTF-8
Значение LANG
/LC_CTYPE
в оболочке.
Проверьте, какую локаль поддерживает ваша оболочка:
locale -a | grep "UTF-8"
Демонстрация проблемы и решения в новой виртуальной машине.
Инициализируйте и подготовьте виртуальную машину (например, используя vagrant
):
vagrant init ubuntu/trusty64; vagrant up; vagrant ssh
See: available Ubuntu boxes..
Печать символов Юникода (например, знака торговой марки, например ™
):
$ 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");'
™
В противном случае попробуйте следующую команду:
$ LC_ALL=C.UTF-8 python -c 'print(u"\u2122");'
™
Ответ 9
Попробуйте это может решить,
# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
Ответ 10
Добавьте строку ниже в начале вашего script (или как вторая строка):
# -*- coding: utf-8 -*-
Это определение кодирования исходного кода на основе python. Дополнительная информация в PEP 263.
Ответ 11
Здесь перефразирование некоторых других так называемых "отписаться" ответов. Существуют ситуации, в которых простое выбрасывание проблемных символов/строк является хорошим решением, несмотря на протесты, озвученные здесь.
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
Предложение: вы могли бы хотеть назвать эту функцию toAscii
вместо этого? Это вопрос предпочтений.
Это было написано для Python 2. Для Python 3, я думаю, вы захотите использовать bytes(obj,"ascii")
а не str(obj)
. Я еще не проверял это, но я в какой-то момент пересмотрю ответ.
Ответ 12
В ракушке:
-
Найдите поддерживаемую локаль UTF-8 с помощью следующей команды:
locale -a | grep "UTF-8"
-
Экспортируйте его перед запуском скрипта, например:
export LC_ALL=$(locale -a | grep UTF-8)
или вручную, как:
export LC_ALL=C.UTF-8
-
Проверьте это, напечатав специальный символ, например ™
:
python -c 'print(u"\u2122");'
Выше проверено в Ubuntu.
Ответ 13
Я всегда помещаю код ниже в первые две строки файлов Python:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
Ответ 14
Простые вспомогательные функции найдены здесь.
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')
Ответ 15
Просто добавьте в переменную encode ('utf-8')
agent_contact.encode('utf-8')
Ответ 16
Пожалуйста, откройте терминал и выполните следующую команду:
export LC_ALL="en_US.UTF-8"
Ответ 17
Я просто использовал следующее:
import unicodedata
message = unicodedata.normalize("NFKD", message)
Проверьте, что говорится в документации:
unicodedata.normalize(form, unistr) Возвращает форму обычной формы для Unistode string unistr. Допустимыми значениями для формы являются "NFC", "NFKC", 'NFD и' NFKD.
В стандарте Unicode определяются различные формы нормализации Unicode строка, основанная на определении канонической эквивалентности и эквивалентность совместимости. В Unicode несколько символов могут быть выраженный в различном ключе. Например, символ U + 00C7 (LATIN CAPITAL ПИСЬМО C CEDILLA) также можно выразить как последовательность U + 0043 (LATIN CAPITAL LETTER C) U + 0327 (КОМБИНИРОВАНИЕ CEDILLA).
Для каждого символа существуют две нормальные формы: нормальная форма C и нормальная форма D. Нормальная форма D (NFD) также известна как каноническая разложение и переводит каждый символ в его разложенную форму. Нормальная форма C (NFC) сначала применяет каноническое разложение, то снова создает комбинированные символы.
В дополнение к этим двум формам существуют две дополнительные нормальные формы основанный на эквивалентности эквивалентности. В Unicode определенные символы которые обычно будут объединены с другими персонажами. Для Например, U + 2160 (ROMAN NUMERAL ONE) на самом деле то же самое, что и U + 0049 (ЛАТИНСКОЕ КАПИТАЛ ПИСЬМО I). Однако он поддерживается в Unicode для совместимость с существующими наборами символов (например, gb2312).
Нормальная форма KD (NFKD) применит разложение совместимости, т.е. заменить все символы совместимости на их эквиваленты. нормальная форма KC (NFKC) сначала применяет разложение совместимости, а затем каноническая композиция.
Даже если две строки в Юникоде нормированы и выглядят одинаково с человеческий читатель, если у вас есть сочетание символов, а другой - нет, они не могут сравниться с равными.
Решает его для меня. Простой и легкий.
Ответ 18
Ниже решение работало для меня, только что добавил
ты "Струна"
(представляющий строку как юникод) перед моей строкой.
result_html = result.to_html(col_space=1, index=False, justify={'right'})
text = u"""
<html>
<body>
<p>
Hello all, <br>
<br>
Here 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)
Ответ 19
Мы столкнулись с этой ошибкой при запуске manage.py migrate
в Django с локализованными устройствами.
Наш источник содержал объявление # -*- coding: utf-8 -*-
, MySQL был правильно настроен для utf8, а Ubuntu имел соответствующий языковой пакет и значения в /etc/default/locale
.
Проблема была просто в том, что в контейнере Django (мы используем docker) отсутствовал LANG
env var.
Установка LANG
на en_US.UTF-8
и перезапуск контейнера перед повторным запуском миграций en_US.UTF-8
проблему.
Ответ 20
У меня просто была эта проблема, и Google привел меня сюда, так что просто чтобы добавить к общим решениям здесь, это то, что сработало для меня:
# 'value' contains the problematic data
unic = u''
unic += value
value = unic
У меня была эта идея после прочтения презентации Ned.
Я не претендую на то, чтобы полностью понять, почему это работает. Поэтому, если кто-нибудь может отредактировать этот ответ или добавить комментарий, я буду этому благодарен.
Ответ 21
Я пробовал много вещей, но нижеследующее решение является лучшим. Устанавливает проблему один раз для всех...
Попробуйте установить системную кодировку по умолчанию как utf-8 в начале, так что все строки кодируются с помощью этого.
Пример -
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
Приведенный выше код устанавливает кодировку по умолчанию как utf-8.
Ответ 22
Увы, это работает в Python 3 по крайней мере...
Python 3
Иногда ошибка заключается в переменных окружения и заканчиваются так
import os
import locale
os.environ["PYTHONIOENCODING"] = "utf-8"
myLocale=locale.setlocale(category=locale.LC_ALL, locale="en_GB.UTF-8")
...
print(myText.encode('utf-8', errors='ignore'))
где ошибки игнорируются при кодировании.
Ответ 23
Это помогает в Python 2.7
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
Это помогает повторно включить sys.setdefaultencoding()
Ответ 24
Если у вас есть что-то вроде packet_data = "This is data"
то сделайте это на следующей строке, сразу после инициализации packet_data
:
unic = u''
packet_data = unic
Ответ 25
Обновление для Python 3.0 и выше. Попробуйте следующее в редакторе python:
locale-gen en_US.UTF-8
export LANG=en_US.UTF-8 LANGUAGE=en_US.en
LC_ALL=en_US.UTF-8
Это устанавливает системную кодировку локали по умолчанию в формат UTF-8.
Более подробно можно прочитать здесь на PEP 538. - Приведение устаревшей локали C к локали на основе UTF-8.
Ответ 26
Многие ответы здесь (например, @agf и @Andbdrew) уже затронули самые непосредственные аспекты вопроса ОП.
Тем не менее, я думаю, что есть один тонкий, но важный аспект, который был в значительной степени проигнорирован и который очень важен для всех, кто, как и я, попал сюда, пытаясь разобраться в кодировках в Python: управление представлением символов в Python 2 и Python 3 сильно отличается, Я чувствую, что большая неразбериха связана с людьми, которые читают о кодировках в Python, не зная версии.
Я предлагаю всем, кто заинтересован в понимании первопричины проблемы OP, начать с прочтения введения Спольски в представления символов и Unicode, а затем перейти к Batchelder в Unicode в Python 2 и Python 3.
Ответ 27
У меня была эта проблема при попытке вывести символы Юникода в stdout
, но с помощью sys.stdout.write
, а не print (чтобы я мог также поддерживать вывод в другой файл).
Из собственной документации BeautifulSoup я решил эту проблему с помощью библиотеки кодеков:
import sys
import codecs
def main(fIn, fOut):
soup = BeautifulSoup(fIn)
# Do processing, with data including non-ASCII characters
fOut.write(unicode(soup))
if __name__ == '__main__':
with (sys.stdin) as fIn: # Don't think we need codecs.getreader here
with codecs.getwriter('utf-8')(sys.stdout) as fOut:
main(fIn, fOut)
Ответ 28
Старайтесь избегать преобразования переменной в str (переменную). Иногда это может вызвать проблему.
Простой совет, чтобы избежать:
try:
data=str(data)
except:
data = data #Don't convert to String
Приведенный выше пример также разрешит ошибку кодирования.
Ответ 29
Эта проблема часто возникает, когда проект django развертывается с использованием Apache. Потому что Apache устанавливает переменную окружения LANG = C в /etc/sysconfig/httpd. Просто откройте файл и прокомментируйте (или измените свой вариант) этот параметр. Или используйте опцию lang команды WSGIDaemonProcess, в этом случае вы сможете установить разные переменные среды LANG для разных виртуальных хостов.