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"
    

Демонстрация проблемы и решения в новой виртуальной машине.

  1. Инициализируйте и подготовьте виртуальную машину (например, используя vagrant):

    vagrant init ubuntu/trusty64; vagrant up; vagrant ssh
    

    See: available Ubuntu boxes..

  2. Печать символов Юникода (например, знака торговой марки, например ):

    $ 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)
    
  3. Сейчас устанавливаем 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.
    
  4. Теперь проблема должна быть решена:

    $ python -c 'print(u"\u2122");'
    ™
    
  5. В противном случае попробуйте следующую команду:

    $ 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

В ракушке:

  1. Найдите поддерживаемую локаль UTF-8 с помощью следующей команды:

    locale -a | grep "UTF-8"
    
  2. Экспортируйте его перед запуском скрипта, например:

    export LC_ALL=$(locale -a | grep UTF-8)
    

    или вручную, как:

    export LC_ALL=C.UTF-8
    
  3. Проверьте это, напечатав специальный символ, например :

    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 для разных виртуальных хостов.