15

UnicodeEncodeError: 'ascii' кодек не может закодировать символ u'\xa0' на позиции 20: номер не в диапазоне (128)

10

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

Проблема в том, что ошибка не всегда воспроизводима; иногда код работает с некоторыми страницами, а иногда выбрасывает ошибку UnicodeEncodeError. Я перепробовал практически все возможные решения, но так и не нашел ничего, что бы работало последовательно и не выдавало ошибок, связанных с юникодом.

Вот часть кода, которая вызывает проблемы:

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)

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

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

5 ответ(ов)

4

Это классическая проблема с юникодом в 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à

Вот и всё!

Проблема в том, что когда вы вызываете str(), Python использует кодировку по умолчанию, чтобы попытаться закодировать байты, которые вы ему передали, а в вашем случае это иногда представления юникодных символов. Чтобы решить проблему, вы должны указать Python, как обрабатывать строку, которую вы ему передаете, используя .encode('ваш_кодек'). В большинстве случаев вам будет достаточно использовать utf-8.

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

2

Я нашел элегантное решение для удаления символов и сохранения строки в формате строки следующим образом:

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

Важно отметить, что использование опции ignore является опасным, так как оно тихо удаляет все символы Unicode (и поддержку интернационализации) в коде, который его использует. Например, если выполнить следующий код:

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

Мы видим, что строка "Malmö" преобразуется в "Malm", и символ "ö" просто отбрасывается. Будьте осторожны с использованием этого метода, если поддержка международных символов важна для вашего приложения.

1

Я пробовал всё, что только можно, но ничего не помогло. После того как погуглил, я нашёл следующее решение, и оно сработало. У меня используется Python 2.7.

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

Для того чтобы найти поддерживаемую локализацию UTF-8 в оболочке, выполните следующие шаги:

  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.

0

На самом деле, я обнаружил, что в большинстве случаев проще всего удалить эти символы. Вот пример кода:

s = mystring.decode('ascii', 'ignore')

Таким образом, все некорректные символы просто игнорируются, и вы получаете строку, содержащую только допустимые символы ASCII.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь