2012-01-06 19 views
16

Tengo un script de Python que carga una página web usando urllib2.urlopen, hace algo de magia, y escupe los resultados usando print. corremos el programa en Windows, así:Peter Piper canalizó un programa de Python, y perdió todos sus caracteres Unicode

python program.py > output.htm 

aquí está el problema:

El urlopen lee datos de un servidor web IIS que da salida a UTF8. Escupe estos mismos datos en la salida, sin embargo ciertos caracteres (como el guión largo que Word siempre inserta para usted en contra de su voluntad porque es más inteligente que usted) se confunden y terminan como – en su lugar.

En una investigación posterior, noté que aunque el servidor web escupe datos UTF8, el archivo output.htm está codificado con el juego de caracteres ISO-8859-1.

Mis preguntas:

  1. Al redirigir un programa de Python a un archivo de salida en Windows, no siempre utilizan este conjunto de caracteres?
  2. Si es así, ¿hay alguna forma de cambiar ese comportamiento?
  3. Si no es así, ¿hay alguna solución? Supongo que podría pasar el output.htm como un parámetro de línea de comando y escribir en ese archivo en lugar de la pantalla, pero tendría que volver a hacer un montón de lógica en mi programa.

¡Gracias por cualquier ayuda!

ACTUALIZACIÓN:

En la parte superior de output.htm añadí:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> 

Sin embargo, no hace ninguna diferencia. Los personajes aún están distorsionados. Si cambio manualmente a UTF-8 en Firefox, el archivo se muestra correctamente. Tanto IE como FF piensan que este archivo es ISO occidental, aunque claramente no lo es.

+1

No es una pipa. Es una redirección. Y es 'print' que está haciendo la codificación. El conducto o la redirección se maneja fuera de Python en Windows. –

+0

Si termina "distorsionado" como dices, entonces la salida * es * UTF-8; lo que sea que esté viendo el archivo lo está interpretando como ISO-8859-1. Es decir, ¿el archivo HTML resultante tiene un prólogo XML que indica la codificación o una metaetiqueta que especifica el tipo de contenido? – slyfox

+3

Bueno, eso no es muy aliterativo. –

Respuesta

8

De sus comentarios y actualización de pregunta parece que los datos están codificados correctamente en UTF-8. Esto significa que usted sólo tiene que decirle a su navegador es UTF-8, ya sea mediante el uso de una lista de materiales, o mejor, añadiendo información de codificación a su documento HTML:

<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
</head> 

que realmente no debería usar una declaración XML si el el documento no es un XML válido.

La mejor y más confiable forma sería servir el archivo a través de HTTP y establecer el encabezado Content-Type: de manera adecuada.

+0

¡Eso lo hizo, gracias! Entonces, supongo que cuando redireccione la secuencia de comandos de Python en Windows, usará la página de códigos predeterminada de Windows (ISO occidental) aunque Python escuche bytes UTF8. Por lo tanto, el archivo tiene una BOM ISO occidental con bytes UTF8. Si cargo el archivo en IE o FF, ve la lista de materiales y la utiliza, ya que ninguna etiqueta 'meta' lo anula. Si publico el archivo en IIS, IIS probablemente lo detecte también y establezca el encabezado 'content-type' en ISO occidental. Creo que usar la metaetiqueta es la mejor solución en esta situación, por lo que '+ 1' es tu respuesta. –

+0

@Mike: No del todo, 'latin1' /' ISO-8859-1' es una extensión de ASCII y no tiene BOM. Tu script funciona perfectamente bien y la redirección también está bien. Lo que salió mal es que su servidor web publicó el '' tipo de contenido '' incorrecto porque su documento tenía * no * UTF-8 BOM, o que el servidor web no especificó ninguna codificación y el navegador acaba de usar su codificación predeterminada, porque no se dijo nada mejor. Por cierto, este no es un problema específico de Windows y podría haber salido mal de manera similar en Linux. –

+0

Oh, en ese caso apuesto a que el archivo no tiene BOM en absoluto. Es probable que Python no solo envíe listas de materiales a la pantalla, y Windows probablemente no las agregue a los archivos creados con '>' –

5

Cuando canaliza un programa de Python a un archivo de salida en Windows, ¿siempre utiliza este juego de caracteres?

Codificación predeterminada utilizada para enviar a la tubería. En mi máquina:

In [5]: sys.getdefaultencoding() 
Out[5]: 'ascii' 

Si no, ¿hay alguna solución?

import sys 
try: 
    sys.setappdefaultencoding('utf-8') 
except: 
    sys = reload(sys) 
    sys.setdefaultencoding('utf-8') 

Ahora toda la salida se codifica a 'UTF-8'.

Creo forma correcta de manejar esta situación sin

rehacer un montón de lógica

es para decodificar todos los datos de su fuente de Internet desde un servidor o página de codificación a unicode, y luego para usar la solución que se muestra arriba para establecer la codificación predeterminada en utf-8.

2

La mayoría de los programas en Windows supondrán que está utilizando la codificación predeterminada de Windows, que será ISO-8859-1 para una instalación en inglés. Esto también se aplica a la salida de ventana de comando. No hay manera de configurar la codificación predeterminada para UTF-8 por desgracia: hay una página de códigos definida para ella, pero no está bien soportada.

Algunos editores reconocerán los caracteres de la BOM al comienzo del archivo y cambiarán a UTF-8, pero eso no está garantizado.

Si está generando HTML, debe incluir la etiqueta correspondiente charset; entonces el navegador lo interpretará correctamente.

Cuestiones relacionadas