Comment encoder des paramètres d'URL en pourcentage en Python?

299

Si je fais

url = "http://example.com?p=" + urllib.quote(query)
  1. Il n'encode /pas %2F(rompt la normalisation OAuth)
  2. Il ne gère pas Unicode (il lève une exception)

Existe-t-il une meilleure bibliothèque?

Paul Tarjan
la source
1
Ce ne sont pas des paramètres d'URL, pour info. Vous devez clarifier.
Jamie Marshall

Réponses:

390

Python 2

De la documentation :

urllib.quote(string[, safe])

Remplacez les caractères spéciaux dans la chaîne à l'aide de l'échappement% xx. Les lettres, les chiffres et les caractères '_.-' ne sont jamais cités. Par défaut, cette fonction est destinée à la citation de la section de chemin de l'URL. Le paramètre optionnel sûr spécifie des caractères supplémentaires qui ne doivent pas être cités - sa valeur par défaut est '/'

Cela signifie que le fait de passer '' en toute sécurité résoudra votre premier problème:

>>> urllib.quote('/test')
'/test'
>>> urllib.quote('/test', safe='')
'%2Ftest'

À propos du deuxième problème, il y a un rapport de bogue à ce sujet ici . Apparemment, il a été corrigé en python 3. Vous pouvez le contourner en encodant en utf8 comme ceci:

>>> query = urllib.quote(u"Müller".encode('utf8'))
>>> print urllib.unquote(query).decode('utf8')
Müller

Au fait, jetez un oeil à urlencode

Python 3

La même chose, sauf remplacer urllib.quotepar urllib.parse.quote.

Nadia Alramli
la source
1
Merci, les deux ont très bien fonctionné. urlencode appelle simplement quoteplus plusieurs fois dans une boucle, ce qui n'est pas la normalisation correcte pour ma tâche (oauth).
Paul Tarjan
6
la spécification: rfc 2396 les définit comme réservés. reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","C'est à cela que traite urllib.quote.
Jeff Sheffield
63
urllib.quotedéplacé vers urlib.parse.quote, depuis Python3.
Hibou57
5
urllib.parse.quote docs
Andreas Haferburg
De plus, dans le cas de l'encodage d'une requête de recherche, il vaut peut-être mieux utiliser quote_plus: docs.python.org/3/library/… 1. Il encode les barres obliques par défaut 2. Il encode également les espaces
Pavel Vergeev
174

En Python 3, urllib.quotea été déplacé vers urllib.parse.quoteet il gère unicode par défaut.

>>> from urllib.parse import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
>>> quote('/El Niño/')
'/El%20Ni%C3%B1o/'
Paolo Moretti
la source
2
Le nom quoteest plutôt vague en tant que global. Il pourrait être plus agréable d'utiliser quelque chose comme urlencode: from urllib.parse import quote as urlencode.
Luc
Notez qu'il ya une fonction nommée urlencodedans urllib.parsedéjà fait quelque chose de complètement différent, vous feriez mieux de choisir un autre nom ou un risque de confusion au sérieux les lecteurs futurs de votre code.
jaymmer
48

Ma réponse est similaire à la réponse de Paolo.

Je pense que le module requestsest beaucoup mieux. C'est basé sur urllib3. Vous pouvez essayer ceci:

>>> from requests.utils import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
Aminah Nuraini
la source
5
requests.utils.quoteest un lien vers python quote. Voir les sources de demande .
Cjkjvfnby
16
requests.utils.quoteest un wrapper de compatibilité mince urllib.quotepour python 2 et urllib.parse.quotepour python 3
Jeff Sheffield
13

Si vous utilisez django, vous pouvez utiliser urlquote:

>>> from django.utils.http import urlquote
>>> urlquote(u"Müller")
u'M%C3%BCller'

Notez que les modifications apportées à Python depuis la publication de cette réponse signifient qu'il s'agit désormais d'un wrapper hérité. Du code source de Django 2.1 pour django.utils.http:

A legacy compatibility wrapper to Python's urllib.parse.quote() function.
(was used for unicode handling on Python 2)
Rick Westera
la source
2

Il vaut mieux l'utiliser urlencodeici. Pas beaucoup de différence pour un seul paramètre mais à mon humble avis, le code est plus clair. (Cela semble déroutant de voir une fonction quote_plus! En particulier ceux provenant d'autres langueurs)

In [21]: query='lskdfj/sdfkjdf/ksdfj skfj'

In [22]: val=34

In [23]: from urllib.parse import urlencode

In [24]: encoded = urlencode(dict(p=query,val=val))

In [25]: print(f"http://example.com?{encoded}")
http://example.com?p=lskdfj%2Fsdfkjdf%2Fksdfj+skfj&val=34

Documents

urlencode: https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlencode

quote_plus: https://docs.python.org/3/library/urllib.parse.html#urllib.parse.quote_plus

balki
la source