it-swarm.com.ru

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)

Я подозреваю, что это потому, что некоторые страницы (или, более конкретно, страницы с некоторых сайтов) могут быть закодированы, в то время как другие могут быть не закодированы. Все сайты базируются в Великобритании и предоставляют данные, предназначенные для потребления в Великобритании, поэтому не возникает проблем, связанных с интернализацией или работой с текстом, написанным на чем-либо, кроме английского.

У кого-нибудь есть идеи относительно того, как решить эту проблему, чтобы я ПОСТОЯННО исправил эту проблему?

1147
Homunculus Reticulli

Вам нужно прочитать Python nicode HOWTO . Эта ошибка самый первый пример .

В основном, прекратите использовать str для преобразования из юникода в кодированный текст/байты.

Вместо этого правильно используйте .encode() для кодирования строки:

p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()

или работать полностью в юникоде.

1236
agf

Это классическая 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 ('what_unicode'). Большую часть времени вы должны быть в порядке, используя utf-8.

Для превосходного изложения по этой теме, см. Выступление Неда Батчелдера на PyCon здесь: http://nedbatchelder.com/text/unipain.html

408
Andbdrew

Я нашел изящную работу для меня, чтобы удалить символы и продолжать сохранять строку как строку следующим образом:

yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')

Важно отметить, что использование параметра ignore - это опасно, потому что он молча отбрасывает любую поддержку юникода (и интернационализации) из кода, который его использует, как показано здесь (convert unicode):

>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii')
'City: Malm'
195
Max Korolevsky

хорошо, я попробовал все, но это не помогло, после поиска в Google я понял следующее, и это помогло. python 2.7 используется.

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
138
Ashwin

Тонкая проблема, приводящая к сбою даже печати, заключается в неправильной установке переменных среды, например. здесь 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à
80
maxpolk

На самом деле я обнаружил, что в большинстве моих случаев просто убрать этих персонажей гораздо проще:

s = mystring.decode('ascii', 'ignore')
25
Phil LaNasa

Для меня то, что сработало, было:

BeautifulSoup(html_text,from_encoding="utf-8")

Надеюсь, это кому-нибудь поможет.

25
Animesh

Попробуйте это может решить,

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
20
Joseph Daudi

Проблема в том, что вы пытаетесь напечатать символ Юникода, но ваш терминал не поддерживает его.

Вы можете попробовать установить пакет 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 в командной консоли.

  • Проверьте, какую локаль поддерживает ваша Shell:

    locale -a | grep "UTF-8"
    

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

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

    vagrant init ubuntu/trusty64; vagrant up; vagrant ssh
    

    Смотрите: доступны коробки с Ubunt .,.

  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");'
    ™
    
18
kenorb

Добавьте строку ниже в начале вашего скрипта (или как вторую строку):

# -*- coding: utf-8 -*-

Это определение кодировки исходного кода python. Больше информации в PEP 26 .

16
Andriy Ivaneyko

Вот перефразировка некоторых других так называемых "отписаться" ответов. Существуют ситуации, в которых простое выбрасывание проблемных символов/строк является хорошим решением, несмотря на протесты, озвученные здесь.

def safeStr(obj):
    try: return str(obj)
    except UnicodeEncodeError:
        return obj.encode('ascii', 'ignore').decode('ascii')
    except: return ""

Тестирование это:

if __== '__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). Я еще не проверял это, но я в какой-то момент пересмотрю ответ.

13
BuvinJ

В ракушке:

  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.

10
kenorb

Я всегда помещаю приведенный ниже код в первые две строки файлов python:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
8
Pereira

Найдены простые вспомогательные функции здесь .

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')
6
Parag Tyagi -morpheus-

Просто добавьте в переменную encode ('utf-8')

agent_contact.encode('utf-8')
4
Kairat Koibagarov

Ниже решение работало для меня, только что добавил

ты "Струна"

(представляющий строку как юникод) перед моей строкой.

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)
3
Aravind Krishnakumar

Я просто использовал следующее:

import unicodedata
message = unicodedata.normalize("NFKD", message)

Проверьте, что документация говорит об этом:

unicodedata.normalize (form, unistr) Возвращает форму обычной формы для строки Unicr Unicode. Допустимые значения для формы: "NFC", "NFKC", "NFD" и "NFKD".

Стандарт Unicode определяет различные формы нормализации строки Unicode, основываясь на определении канонической эквивалентности и эквивалентности совместимости. В Unicode несколько символов могут быть выражены по-разному. Например, символ U + 00C7 (LATIN CAPITAL LETTER 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 (LATIN CAPITAL LETTER I). Однако он поддерживается в Юникоде для совместимости с существующими наборами символов (например, gb2312).

Нормальная форма KD (NFKD) будет применять декомпозицию совместимости, то есть заменять все символы совместимости их эквивалентами. Нормальная форма KC (NFKC) сначала применяет декомпозицию совместимости, а затем каноническую композицию.

Даже если две строки Юникода нормализованы и выглядят одинаково для читателя-человека, если одна содержит комбинированные символы, а другая - нет, они могут не совпадать.

Решает это для меня. Просто и легко.

3
Drag0

Пожалуйста, откройте терминал и выполните следующую команду:

export LC_ALL="en_US.UTF-8"
2
Hồ Ngọc Vượng

Эта ошибка возникла при запуске manage.py migrate в Django с локализованными приборами.

Наш источник содержал объявление # -*- coding: utf-8 -*-, MySQL был правильно настроен для utf8, а Ubuntu имел соответствующий языковой пакет и значения в /etc/default/locale.

Проблема заключалась просто в том, что в контейнере Django (мы используем docker) отсутствовала переменная LANG env.

Установка LANG в en_US.UTF-8 и перезапуск контейнера перед повторным запуском миграций устранили проблему.

2
followben

У меня просто была эта проблема, и Google привел меня сюда, так что, чтобы добавить здесь общие решения, вот что сработало для меня:

# 'value' contains the problematic data
unic = u''
unic += value
value = unic

У меня была эта идея после прочтения презентация Неда .

Я не утверждаю, что полностью понимаю, почему это работает, хотя. Так что если кто-то может отредактировать этот ответ или добавить комментарий, чтобы объяснить, я буду благодарен.

1
pepoluan

Увы, это работает как минимум в Python 3 ...

Python

Иногда ошибка заключается в переменных окружения и заканчиваются так

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'))

где ошибки игнорируются при кодировании.

0
hhh

Многие ответы здесь (например, @agf и @Andbdrew) уже затронули самые непосредственные аспекты вопроса OP.

Тем не менее, я думаю, что есть один тонкий, но важный аспект, который был в значительной степени проигнорирован и который имеет большое значение для всех, кто, как я, попал сюда при попытке разобраться в кодировках в Python: Python 2 против Python 3 управление представлением символов сильно отличается . Я чувствую, что большая неразбериха связана с людьми, читающими о кодировках в Python, не осведомленными о версии.

Я предлагаю всем, кто интересуется пониманием первопричины проблемы OP, начать с прочтения Spolsky's введения в представления символов и Unicode, а затем перейти к Batchelder в Unicode в Python 2 и Python 3.

0
Simón Ramírez Amaya

Если у вас есть что-то вроде packet_data = "This is data", сделайте это на следующей строке, сразу после инициализации packet_data:

unic = u''
packet_data = unic
0
Nandan Kulkarni

Обновление для 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 .

0
ZF007

Это помогает в python 2.7

import sys
reload(sys)   
sys.setdefaultencoding('utf-8')

Это помогает повторно включить sys.setdefaultencoding ()

0
Edward Okech

У меня возникла эта проблема при попытке вывести символы Юникода в stdout, но с помощью sys.stdout.write, а не печати (чтобы я мог также поддерживать вывод в другой файл).

из собственной документации 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 __== '__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)
0
palswim