2010-06-27 18 views
21

Me estoy cansando de tratar de descubrir por qué este código funciona en Python 2 y no en Python 3. Estoy tratando de tomar una página de json y luego analizar eso. Aquí está el código en Python 2:Python 2 vs. Python 3 - formatos urllib

import urllib, json 
response = urllib.urlopen("http://reddit.com/.json") 
content = response.read() 
data = json.loads(content) 

I pensaron el código equivalente en Python 3 sería la siguiente:

import urllib.request, json 
response = urllib.request.urlopen("http://reddit.com/.json") 
content = response.read() 
data = json.loads(content) 

Pero sopla en mi cara, porque los datos devueltos por lectura () es un tipo de "bytes". Sin embargo, no puedo por mi vida convertirlo en algo que JSON pueda analizar. Sé por las cabeceras que reddit está intentando enviar UTF-8 de nuevo a mí, pero me parece que no puede obtener los bytes que se decodifican en UTF-8:

import urllib.request, json 
response = urllib.request.urlopen("http://reddit.com/.json") 
content = response.read() 
data = json.loads(content.decode("utf8")) 

¿Qué estoy haciendo mal?

Editar: el problema es que no puedo obtener los datos en un estado utilizable; a pesar de que json carga los datos, parte de ellos no se puede mostrar, y quiero poder imprimir los datos en la pantalla.

Segunda edición: Parece que el problema tiene más que ver con la impresión que con el análisis. La respuesta de Alex proporciona una forma para que el script funcione en Python 3, estableciendo el IO en utf8. Pero aún queda una pregunta: ¿por qué el código funcionaba en Python 2, pero no en Python 3?

Respuesta

15

Es probable que el código que publique se deba a operaciones de corte y pegado erróneas porque es claramente incorrecto en ambas versiones (f.read() falla porque no se ha definido f barename).

En Py3, ur = response.decode('utf8') funciona perfectamente bien para mí, al igual que el json.loads(ur). Tal vez las copys-and-paste incorrectas afectaron sus intentos de conversión de 2 a 3.

+0

Vaya, corregiré los errores de código ... Intenté reformatearlo para visualizarlo pero lo arruiné todo en el proceso. : P Independientemente, no puedo ver los datos después de analizarlos (usando una simple "impresión (datos)") porque me da errores de mapa de correspondencia. –

+0

@Daniel, los problemas posteriores a la obtención de los datos parecen ser una pregunta aparte de la obtención de los datos (a los que parece responder mi respuesta), aunque aparentemente no está de acuerdo, ya que no lo hizo. ¡incluso lo voté!). Si con 'data' te refieres a' json.loads (response) ', puedo' imprimirlo 'sin ningún problema (en mi Mac Terminal.app, que admite UTF-8). ¿Cuál es tu sys.stdout.encoding? ¿Ha configurado correctamente la variable de entorno 'PYTHONIOENCODING: Codificación [: errors] utilizada para stdin/stdout/stderr' antes de iniciar Python 3? Etc, etc. - problemas totalmente diferentes, ver. –

+0

Lo siento si no estaba claro al principio. El problema principal es que no puedo * usar * los datos después del análisis, por la razón que sea (la impresión es solo el comienzo de la misma, si no puedo imprimirla, en algún momento me voy a encontrar con problemas) leyendo los datos). Revisaré la codificación, basta con decir que no funciona en mi máquina W7. –

0

Consulte that respuesta en otra pregunta relacionada con Unicode.

Ahora: el Python 3 str (que era el tipo de Python 2 unicode) es un objeto idealizado, en el sentido de que se trata de "caracteres", no de "bytes". Estos caracteres, para ser utilizados para/desde datos de disco/red, deben codificarse-decodificarse-desde bytes mediante una "tabla de conversión", a.k.a que codifica una página de códigos ak. Debido a la variedad del sistema operativo, Python históricamente evitó adivinar cuál debería ser esa codificación; esto ha ido cambiando a lo largo de los años, pero sigue siendo válido el principio de "Frente a la ambigüedad, rehúsa la tentación de adivinar".

Afortunadamente, un servidor web hace que su trabajo sea más fácil. Su response anterior debería darle toda la información adicional necesaria:

>>> response.headers['content-type'] 
'application/json; charset=UTF-8' 

Por lo tanto, cada vez que se emite una petición a un servidor web, comprobar la cabecera Content-Type para un valor conjunto de caracteres, y decodificar los datos de la solicitud en Unicode (Python 3: bytes.decode(charset)str) usando ese juego de caracteres.

6

Dependiendo de la versión de su pitón, debe elegir la biblioteca correcta.

para el pitón 3,5

import urllib.request 
data = urllib.request.urlopen(url).read().decode('utf8') 

para Python 2.7

import urllib 
url = serviceurl + urllib.urlencode({'sensor':'false', 'address': address}) 
uh = urllib.urlopen(url) 
+0

Es posible que desee proporcionar una explicación para aclarar su código. – GabrielOshiro