web-dev-qa-db-fra.com

Encodage / décodage d'URL avec Python

J'essaie d'encoder et de stocker et de décoder les arguments dans Python et de me perdre quelque part en cours de route. Voici mes étapes:

1) J'utilise gtm_stringByEscapingForURLArgument De la boîte à outils Google pour convertir correctement une NSString pour la passer en arguments HTTP.

2) Sur mon serveur (python), je stocke ces arguments de chaîne comme quelque chose comme u'1234567890-/:;()$&@".,?!\'[]{}#%^*+=_\\|~<>\u20ac\xa3\xa5\u2022.,?!\'' (notez que ce sont les touches standard sur un clavier d'iphone dans la vue "123" et la vue "# + =" , les caractères \u et \x contiennent des préfixes monétaires comme la livre, le yen, etc.)

3) J'appelle urllib.quote(myString,'') sur cette valeur stockée, vraisemblablement pour les% échapper pour le transport vers le client afin que le client puisse échapper à eux.

Le résultat est que j'obtiens une exception lorsque j'essaie de consigner le résultat de% s'échappant. Existe-t-il une étape cruciale que j'oublie qui doit être appliquée à la valeur stockée au format\u et\x afin de la convertir correctement pour l'envoi via http?

pdate: La suggestion marquée comme réponse ci-dessous a fonctionné pour moi. Cependant, je fournis quelques mises à jour pour répondre aux commentaires ci-dessous.

L'exception que j'ai reçue a cité un problème avec \u20ac. Je ne sais pas si c'était un problème avec cela spécifiquement, plutôt que le fait qu'il s'agissait du premier caractère unicode de la chaîne.

Ce caractère \u20ac Est l'unicode du symbole 'euro'. J'ai trouvé que j'avais des problèmes avec ça sauf si j'utilisais la méthode urllib2 quote.

47
Joey

l'url encodant un unicode "brut" n'a pas vraiment de sens. Ce que vous devez faire est d'abord .encode("utf8") pour avoir un codage d'octets connu puis .quote() cela.

La sortie n'est pas très jolie mais elle devrait être un encodage uri correct.

>>> s = u'1234567890-/:;()$&@".,?!\'[]{}#%^*+=_\|~<>\u20ac\xa3\xa5\u2022.,?!\''
>>> urllib2.quote(s.encode("utf8"))
'1234567890-/%3A%3B%28%29%24%26%40%22.%2C%3F%21%27%5B%5D%7B%7D%23%25%5E%2A%2B%3D_%5C%7C%7E%3C%3E%E2%82%AC%C2%A3%C2%A5%E2%80%A2.%2C%3F%21%27'

N'oubliez pas que vous devrez à la fois unquote() et decode() ceci pour l'imprimer correctement si vous déboguez ou autre.

>>> print urllib2.unquote(urllib2.quote(s.encode("utf8")))
1234567890-/:;()$&@".,?!'[]{}#%^*+=_\|~<>€£¥•.,?!'
>>> # oops, nasty  means we've got a utf8 byte stream being treated as an ascii stream
>>> print urllib2.unquote(urllib2.quote(s.encode("utf8"))).decode("utf8")
1234567890-/:;()$&@".,?!'[]{}#%^*+=_\|~<>€£¥•.,?!'

C'est en fait ce que font les fonctions Django mentionnées dans une autre réponse.

Les fonctions Django.utils.http.urlquote () et Django.utils.http.urlquote_plus () sont des versions des urllib.quote () et urllib.quote_plus () standard de Python qui fonctionnent avec des caractères non ASCII. (Les données sont converties en UTF-8 avant l'encodage.)

Soyez prudent si vous appliquez d'autres citations ou encodages pour ne pas modifier les choses.

70
pycruft

je veux seconder la remarque de pycruft. Les protocoles Web ont évolué au fil des décennies et la gestion des divers ensembles de conventions peut être lourde. maintenant, les URL ne sont explicitement pas définies pour les caractères, mais uniquement pour les octets (octets). comme une coïncidence historique, les URL sont l'un des endroits où vous ne pouvez que supposer, mais pas appliquer ou attendre en toute sécurité un encodage. cependant, il existe une convention pour préférer latin-1 et utf-8 aux autres codages ici. pendant un certain temps, il semblait que ' nicode pour cent s'échappe ' serait l'avenir, mais ils n'ont jamais pris le dessus.

il est d'une importance primordiale d'être pointilleusement pointilleux dans ce domaine sur la différence entre les objets unicode et les octets strings (in Python <3.0; c'est, de manière confuse, str objets unicode et bytes/bytearray objets dans Python> = 3.0). Malheureusement, d'après mon expérience, c'est pour un certain nombre de raisons assez difficiles de séparer proprement les deux concepts dans Python 2.x.

encore plus OT, lorsque vous souhaitez recevoir des requêtes HTTP tierces, vous ne pouvez absolument pas vous fier aux URL envoyées en octets à pourcentage échappé et codés en utf-8: il peut y avoir à la fois _ %uxxxx y échapper, et au moins firefox 2.x utilisé pour coder les URL en latin-1 lorsque cela est possible, et en utf-8 uniquement lorsque cela est nécessaire.

4
flow

Vous n'avez pas de chance avec stdlib, urllib.quote ne fonctionne pas avec unicode. Si vous utilisez Django vous pouvez utiliser Django.utils.http.urlquote qui fonctionne correctement avec unicode

2
almir karic