2009-09-10 32 views
0

Lorsque je tente de récupérer des informations de l'API Google météo à l'adresse suivante,Python urllib, minidom et analyse syntaxique des caractères internationaux

http://www.google.com/ig/api?weather=Munich,Germany&hl=de

puis essayer de l'analyser avec minidom, je reçois l'erreur que le document n'est pas bien formé.

J'utilise le code suivant

sock = urllib.urlopen(url) # above mentioned url 
doc = minidom.parse(sock) 

Je pense que les caractères allemands dans la réponse est la cause de l'erreur.

Quelle est la bonne façon de procéder?

+0

Pourquoi Google envoie-t-il des données XML dans une nouvelle API comme ISO-8859-1? C'est terrible. –

+0

Ce fil (http://blog.emerick.org/2008/05/07/google-weather-api-feed-documentation/) suggère qu'il ne s'agit pas d'une API google "officielle". – ChristopheD

Répondre

1

L'encodage envoyé dans les en-têtes est iso-8859-1 selon urllib.urlopen de python (bien que les en-têtes HTTP de firefox semblent être en désaccord avec moi dans ce cas - rapports utf-8). Dans le fichier XML lui-même, il n'y a pas d'encodage spécifié -> c'est pourquoi xml.dom.minidom suppose que c'est utf-8.

Donc, ce qui suit devrait résoudre ce problème spécifique:

import urllib 
from xml.dom import minidom 

sock = urllib.urlopen('http://www.google.com/ig/api?weather=Munich,Germany&hl=de') 
s = sock.read() 
encoding = sock.headers['Content-type'].split('charset=')[1] # iso-8859-1 
doc = minidom.parseString(s.decode(encoding).encode('utf-8')) 

Modifier: Je l'ai mis à jour cette réponse après le commentaire de Glenn Maynard. J'ai pris la liberté de prendre une ligne de la réponse de Lennert Regebro.

+0

'Content-Type: text/xml; charset = ISO-8859-1' –

+0

Très étrange. Sur Firefox 3.013 (Linux), le plugin Live HTTP Headers rapporte Content-Type: text/xml; jeu de caractères = UTF-8 . Les en-têtes de la poignée urllib.urlopen signalent cependant l'iso-8859-1. Je devrais probablement mettre à jour le code alors. – ChristopheD

+0

J'ai choisi cette réponse parce que je l'ai d'abord lu et cela a fonctionné! Les deux réponses sont super! Merci. – rangalo

2

Cela semble fonctionner:

sock = urllib.urlopen(url) 
# There is a nicer way for this, but I don't remember right now: 
encoding = sock.headers['Content-type'].split('charset=')[1] 
data = sock.read() 
dom = minidom.parseString(data.decode(encoding).encode('ascii', 'xmlcharrefreplace')) 

je suppose que minidom ne gère rien non ascii. Vous pourriez vouloir regarder dans lxml à la place, c'est le cas.

+1

Citation de http://evanjones.ca/python-utf8.html: "Minidom peut gérer n'importe quel format de chaîne d'octets, tel que Latin-1 ou UTF-16, mais il ne fonctionnera que si le document XML a un déclaration de codage (par exemple, ). Si la déclaration de codage est manquante, minidom suppose que c'est UTF-8 In est une bonne habitude d'inclure une déclaration de codage sur tous vos documents XML, afin de garantir la compatibilité sur tous les systèmes. " – ChristopheD

+0

La recommandation lxml est bonne si ... – ChristopheD