UnicodeEncodeError: el codec ‘ascii’ no puede codificar el carácter u ‘\ xa0’ en la posición 20: ordinal no está dentro del rango (128)

Tengo problemas para tratar con caracteres Unicode del texto obtenido de diferentes páginas web (en diferentes sitios). Estoy usando BeautifulSoup.

El problema es que el error no siempre es reproducible; a veces funciona con algunas páginas y, a veces, barfs lanzando un UnicodeEncodeError . He intentado casi todo lo que puedo pensar, y sin embargo, no he encontrado nada que funcione de manera consistente sin lanzar algún tipo de error relacionado con Unicode.

Una de las secciones de código que está causando problemas se muestra a continuación:

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

Aquí hay un seguimiento de stack producido en ALGUNAS cadenas cuando se ejecuta el fragmento de código anterior:

 Traceback (most recent call last): File "foobar.py", line 792, in  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) 

Sospecho que esto se debe a que algunas páginas (o más específicamente, las páginas de algunos de los sitios) pueden estar codificadas, mientras que otras pueden estar sin codificar. Todos los sitios tienen su sede en el Reino Unido y proporcionan datos destinados al consumo del Reino Unido, por lo que no hay problemas relacionados con la internalización o el tratamiento de texto escrito en otra cosa que no sea el inglés.

¿Alguien tiene alguna idea sobre cómo resolver esto para que así pueda solucionar este problema DE FORMA CONSISTENTE?

Necesitas leer el CÓMO de Python Unicode . Este error es el primer ejemplo .

Básicamente, deje de usar str para convertir de unicode a texto codificado / bytes.

En su lugar, use apropiadamente .encode() para codificar la cadena:

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

O trabajar completamente en Unicode.

Este es un clásico punto de dolor Python Unicode! Considera lo siguiente:

 a = u'bats\u00E0' print a => batsà 

Todo bien hasta ahora, pero si llamamos a str (a), veamos qué sucede:

 str(a) Traceback (most recent call last): File "", line 1, in  UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128) 

Oh chapuzón, eso no va a hacer ningún bien a nadie! Para corregir el error, codifique los bytes explícitamente con .encode y dígale a python qué códec usar:

 a.encode('utf-8') => 'bats\xc3\xa0' print a.encode('utf-8') => batsà 

Voil \ u00E0!

El problema es que cuando llamas a str (), python usa la encoding de caracteres predeterminada para intentar y codificar los bytes que le diste, que en tu caso a veces son representaciones de caracteres Unicode. Para solucionar el problema, debes decirle a Python cómo lidiar con la cadena que le das usando .encode (‘whatever_unicode’). La mayoría de las veces, debería estar bien usando utf-8.

Para una excelente exposición sobre este tema, vea la charla de PyCon de Ned Batchelder aquí: http://nedbatchelder.com/text/unipain.html

Encontré un trabajo elegante alrededor para que elimine los símbolos y continúe manteniendo la cadena como cadena de la siguiente manera:

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

Es importante notar que usar la opción de ignorar es peligroso porque descarta silenciosamente cualquier soporte de Unicode (e internacionalización) del código que lo usa, como se ve aquí (convertir unicode):

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

Bueno, lo intenté todo, pero no me ayudó. Después de buscar en Google, calculé lo siguiente y me ayudó. Python 2.7 está en uso.

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

Un problema sutil que causa que incluso la impresión falle es tener las variables de entorno configuradas incorrectamente, por ejemplo. aquí LC_ALL se establece en “C”. En Debian desalientan configurarlo: Debian wiki en Locale

 $ echo $LANG en_US.utf8 $ echo $LC_ALL C $ python -c "print (u'voil\u00e0')" Traceback (most recent call last): File "", line 1, in  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à 

De hecho, descubrí que en la mayoría de mis casos, eliminar esos personajes es mucho más simple:

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

Para mí, lo que funcionó fue:

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

Espero que esto ayude a alguien.

Intenta esto podría resolver,

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

Agregue la línea a continuación al comienzo de su script (o como segunda línea):

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

Esa es la definición de la encoding del código fuente de Python. Más información en PEP 263 .

El problema es que está intentando imprimir un carácter Unicode, pero su terminal no lo admite.

Puedes intentar instalar language-pack-en para arreglar eso:

 sudo apt-get install language-pack-en 

que proporciona actualizaciones de datos de traducción al inglés para todos los paquetes compatibles (incluido Python). Instale un paquete de idioma diferente si es necesario (dependiendo de los caracteres que intenta imprimir).

En algunas distribuciones de Linux es necesario para asegurarse de que las configuraciones regionales predeterminadas en inglés están configuradas correctamente (por lo que los caracteres Unicode pueden ser manejados por shell / terminal). A veces es más fácil instalarlo, que configurarlo manualmente.

Luego, cuando escriba el código, asegúrese de usar la encoding correcta en su código.

Por ejemplo:

 open(foo, encoding='utf-8') 

Si aún tiene un problema, verifique dos veces la configuración de su sistema, como:

  • Su archivo de configuración regional ( /etc/default/locale ), que debería tener, por ejemplo,

     LANG="en_US.UTF-8" LC_ALL="en_US.UTF-8" 

    o:

     LC_ALL=C.UTF-8 LANG=C.UTF-8 
  • Valor de LANG / LC_CTYPE en shell.

  • Compruebe qué configuración regional admite su shell mediante:

     locale -a | grep "UTF-8" 

Demostrando el problema y la solución en VM nueva.

  1. Inicialice y aprovisione la máquina virtual (por ejemplo, usando vagrant ):

     vagrant init ubuntu/trusty64; vagrant up; vagrant ssh 

    Ver: cajas de Ubuntu disponibles . .

  2. Imprimir caracteres Unicode (como el signo de marca like ):

     $ python -c 'print(u"\u2122");' Traceback (most recent call last): File "", line 1, in  UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 0: ordinal not in range(128) 
  3. Ahora instalando 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. Ahora el problema debe ser resuelto:

     $ python -c 'print(u"\u2122");' ™ 
  5. De lo contrario, pruebe el siguiente comando:

     $ LC_ALL=C.UTF-8 python -c 'print(u"\u2122");' ™ 

Aquí hay una repetición de algunas de las llamadas respuestas “de salida”. Hay situaciones en las que simplemente tirar los caracteres / cuerdas molestos es una buena solución, a pesar de las protestas que se expresan aquí.

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

Probándolo:

 if __name__ == '__main__': print safeStr( 1 ) print safeStr( "test" ) print u'98\xb0' print safeStr( u'98\xb0' ) 

Resultados:

 1 test 98° 98 

Sugerencia: es posible que desee nombrar esta función como toAscii en toAscii lugar? Esa es una cuestión de preferencia.

En shell:

  1. Encuentre el entorno local UTF-8 compatible con el siguiente comando:

     locale -a | grep "UTF-8" 
  2. Exportarlo, antes de ejecutar el script, por ejemplo:

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

    o manualmente como:

     export LC_ALL=C.UTF-8 
  3. Pruébelo imprimiendo un carácter especial, ej. :

     python -c 'print(u"\u2122");' 

Anteriormente probado en Ubuntu.

Siempre coloco el código a continuación en las dos primeras líneas de los archivos de python:

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

Funciones de ayuda simples que se encuentran aquí .

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

Solo agregue a una encoding variable (‘utf-8’)

 agent_contact.encode('utf-8') 

Acabo de usar lo siguiente:

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

Compruebe lo que dice la documentación al respecto:

unicodedata.normalize (form, unistr) Devuelve la forma normal para la cadena Unicode unistr. Los valores válidos para la forma son ‘NFC’, ‘NFKC’, ‘NFD’ y ‘NFKD’.

El estándar de Unicode define varias formas de normalización de una cadena de Unicode, según la definición de equivalencia canónica y la equivalencia de compatibilidad. En Unicode, varios caracteres se pueden express de varias maneras. Por ejemplo, el carácter U + 00C7 (LETRA MAYÚSCULA LETRA C CON CEDILLA) también se puede express como la secuencia U + 0043 (LATINA CAPITAL LETRA C) U + 0327 (COMBINANDO CEDILLA).

Para cada personaje, hay dos formas normales: la forma normal C y la forma normal D. La forma normal D (NFD) también se conoce como descomposición canónica y traduce cada carácter a su forma descompuesta. La forma normal C (NFC) primero aplica una descomposición canónica, luego vuelve a componer los caracteres pre-combinados.

Además de estas dos formas, hay dos formas normales adicionales basadas en la equivalencia de compatibilidad. En Unicode, se admiten ciertos caracteres que normalmente se unificarían con otros caracteres. Por ejemplo, U + 2160 (ROMAN NUMERAL ONE) es realmente lo mismo que U + 0049 (LETRA MAYÚSCULA LATINA I). Sin embargo, es compatible con Unicode para la compatibilidad con conjuntos de caracteres existentes (por ejemplo, gb2312).

La forma normal KD (NFKD) aplicará la descomposición de compatibilidad, es decir, reemplazará todos los caracteres de compatibilidad con sus equivalentes. La forma normal KC (NFKC) primero aplica la descomposición de compatibilidad, seguida de la composición canónica.

Incluso si dos cadenas de Unicode están normalizadas y tienen el mismo aspecto que un lector humano, si una tiene caracteres combinados y la otra no, pueden no ser iguales.

Lo resuelve por mi. Simple y fácil.

Debajo de la solución funcionó para mí, Sólo añadido

u “cadena”

(representando la cadena como unicode) antes de mi cadena.

 result_html = result.to_html(col_space=1, index=False, justify={'right'}) text = u"""   

Hello all,

Here's weekly summary report. Let me know if you have any questions.

Data Summary


{0}

Thanks,

Data Team

""".format(result_html)

Nos encontramos con este error cuando manage.py migrate en Django con dispositivos localizados.

Nuestra fuente contenía la statement # -*- coding: utf-8 -*- , MySQL se configuró correctamente para utf8 y Ubuntu tenía el paquete de idioma y los valores adecuados en /etc/default/locale .

El problema era simplemente que al contenedor Django (usamos la ventana acoplable) le faltaba la var.

La configuración de LANG en en_US.UTF-8 y el reinicio del contenedor antes de volver a ejecutar las migraciones solucionó el problema.

Acabo de tener este problema y Google me guió aquí, así que solo para agregar a las soluciones generales aquí, esto es lo que funcionó para mí:

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

Tuve esta idea después de leer la presentación de Ned .

Sin embargo, no pretendo entender completamente por qué funciona esto. Entonces, si alguien puede editar esta respuesta o hacer un comentario para explicar, se lo agradeceré.

Si tienes algo como packet_data = "This is data" , hazlo en la siguiente línea, justo después de inicializar packet_data :

 unic = u'' packet_data = unic 

Por favor abre la terminal y dispara el siguiente comando:

 export LC_ALL="en_US.UTF-8" 

Actualización para Python 3.0 y versiones posteriores. Intenta lo siguiente en el editor de python:

 locale-gen en_US.UTF-8 export LANG=en_US.UTF-8 LANGUAGE=en_US.en LC_ALL=en_US.UTF-8 

Esto establece la encoding de la configuración regional predeterminada del sistema en el formato UTF-8.

Se puede leer más aquí en PEP 538 – Cómo forzar la configuración regional C heredada a una configuración regional basada en UTF-8 .

Muchas respuestas aquí (@agf y @Andbdrew por ejemplo) ya han abordado los aspectos más inmediatos de la pregunta OP.

Sin embargo, creo que hay un aspecto sutil pero importante que se ha ignorado en gran medida y que importa mucho para todos los que, como yo, terminamos aquí mientras intentamos darle sentido a las codificaciones en Python: Python 2 vs Python 3: la gestión de la representación de personajes es tremendamente diferente. . Siento que una gran parte de la confusión tiene que ver con las personas que leen sobre codificaciones en Python sin ser conscientes de la versión.

Sugiero que cualquier persona interesada en comprender la causa raíz del problema de OP comience por leer la introducción de Spolsky a las representaciones de caracteres y Unicode y luego pasar a Batchelder en Unicode en Python 2 y Python 3.

Tuve este problema al intentar enviar caracteres Unicode a la salida sys.stdout.write , pero con sys.stdout.write , en lugar de imprimir (de modo que también podría admitir la salida en un archivo diferente).

A partir de la propia documentación de BeautifulSoup , resolví esto con la biblioteca de codecs:

 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) 

Por desgracia esto funciona en Python 3 al menos …

Python 3

A veces el error se encuentra en las variables de entorno y lo acompaña

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

donde los errores son ignorados en la encoding.