Comment urlencode une chaîne de requête en Python?

552

J'essaie de coder cette chaîne en url avant de soumettre.

queryString = 'eventName=' + evt.fields["eventName"] + '&' + 'eventDescription=' + evt.fields["eventDescription"]; 
James
la source

Réponses:

561

Vous devez passer vos paramètres urlencode()sous forme de mappage (dict) ou de séquence de 2 tuples, comme:

>>> import urllib
>>> f = { 'eventName' : 'myEvent', 'eventDescription' : 'cool event'}
>>> urllib.urlencode(f)
'eventName=myEvent&eventDescription=cool+event'

Python 3 ou supérieur

Utilisation:

>>> urllib.parse.urlencode(f)
eventName=myEvent&eventDescription=cool+event

Notez que cela ne fait pas de codage d'URL dans le sens couramment utilisé (regardez la sortie). Pour cette utilisation urllib.parse.quote_plus.

bgporter
la source
12
"Notez que le fichier urllib.urlencode ne fait pas toujours l'affaire. Le problème est que certains services se soucient de l'ordre des arguments, qui est perdu lorsque vous créez le dictionnaire. Pour de tels cas, urllib.quote_plus est meilleur, comme l'a suggéré Ricky. "
Blairg23
16
Techniquement, c'est un bug dans les services, non?
holdenweb
5
et comment procéder si vous voulez simplement sécuriser une URL de chaîne, sans construire une chaîne d'argument de requête complète?
Mike 'Pomax' Kamermans
1
@ Mike'Pomax'Kamermans - voir par exemple stackoverflow.com/questions/12082314/… ou la réponse de Ricky à cette question.
bgporter
1
@ bk0 il semble que votre méthode ne soit valide que pour les dictionnaires et non pour les chaînes.
JD Gamboa
1021

Python 2

Ce que vous recherchez, c'est urllib.quote_plus:

>>> urllib.quote_plus('string_of_characters_like_these:$#@=?%^Q^$')
'string_of_characters_like_these%3A%24%23%40%3D%3F%25%5EQ%5E%24'

Python 3

En Python 3, le urllibpackage a été divisé en composants plus petits. Vous utiliserez urllib.parse.quote_plus(notez le parsemodule enfant)

import urllib.parse
urllib.parse.quote_plus(...)
Ricky
la source
4
Merci! Dans mon cas cependant, je dois mettre:import urllib.parse ... urllib.parse.quote_plus(query)
ivkremer
3
très bien, mais pourquoi ne pas utiliser Unicode? si la chaîne url est Unicode, je dois la coder en UTF-8.Y a-t-il une autre façon de le faire?
Karl Doenitz
7
Cela fonctionne très bien, mais je n'ai pas pu accéder à certains services en ligne (REST) ​​jusqu'à ce que j'ajoute ce paramètre safe = '; /?: @ & = + $,'
rovyko
J'ai essayé cela en Python 3 mais je n'ai pas pu: stackoverflow.com/questions/40557606/…
amphibient
1
python3 -c "import urllib.parse, sys; print(urllib.parse.quote_plus(sys.argv[1])) "string to encode"pour un one liner sur la ligne de commande
Amos Joshua
52

Essayez les demandes au lieu de urllib et vous n'aurez pas à vous soucier de l'urlencode!

import requests
requests.get('http://youraddress.com', params=evt.fields)

ÉDITER:

Si vous avez besoin de paires nom-valeur ordonnées ou de plusieurs valeurs pour un nom, définissez les paramètres comme suit:

params=[('name1','value11'), ('name1','value12'), ('name2','value21'), ...]

au lieu d'utiliser un dictionnaire.

Barney
la source
5
Cela ne résout pas le problème de la commande des paires de valeurs de nom, cela nécessite également l'autorisation d'installer des bibliothèques externes qui pourraient ne pas être réalisables pour le projet.
dreftymac
J'ai posté le code minimal qui fonctionnerait pour l'OP. L'OP n'a pas demandé de paires commandées mais c'est également faisable, voir ma mise à jour.
Barney
@dreftymac: cela concerne la commande (bien que cela ne fasse pas partie de la question), veuillez lire ma réponse mise à jour.
Barney
36

Le contexte

  • Python (version 2.7.2)

Problème

  • Vous souhaitez générer une chaîne de requête encodée en url.
  • Vous disposez d'un dictionnaire ou d'un objet contenant les paires nom-valeur.
  • Vous voulez pouvoir contrôler l'ordre de sortie des paires nom-valeur.

Solution

  • urllib.urlencode
  • urllib.quote_plus

Pièges

Exemple

Ce qui suit est une solution complète, y compris comment gérer certains pièges.

### ********************
## init python (version 2.7.2 )
import urllib

### ********************
## first setup a dictionary of name-value pairs
dict_name_value_pairs = {
  "bravo"   : "True != False",
  "alpha"   : "http://www.example.com",
  "charlie" : "hello world",
  "delta"   : "1234567 !@#$%^&*",
  "echo"    : "[email protected]",
  }

### ********************
## setup an exact ordering for the name-value pairs
ary_ordered_names = []
ary_ordered_names.append('alpha')
ary_ordered_names.append('bravo')
ary_ordered_names.append('charlie')
ary_ordered_names.append('delta')
ary_ordered_names.append('echo')

### ********************
## show the output results
if('NO we DO NOT care about the ordering of name-value pairs'):
  queryString  = urllib.urlencode(dict_name_value_pairs)
  print queryString 
  """
  echo=user%40example.com&bravo=True+%21%3D+False&delta=1234567+%21%40%23%24%25%5E%26%2A&charlie=hello+world&alpha=http%3A%2F%2Fwww.example.com
  """

if('YES we DO care about the ordering of name-value pairs'):
  queryString  = "&".join( [ item+'='+urllib.quote_plus(dict_name_value_pairs[item]) for item in ary_ordered_names ] )
  print queryString
  """
  alpha=http%3A%2F%2Fwww.example.com&bravo=True+%21%3D+False&charlie=hello+world&delta=1234567+%21%40%23%24%25%5E%26%2A&echo=user%40example.com
  """ 
dreftymac
la source
23

Essaye ça:

urllib.pathname2url(stringToURLEncode)

urlencodene fonctionnera pas car il ne fonctionne que sur les dictionnaires. quote_plusn'a pas produit la sortie correcte.

Charlie
la source
C'est vraiment utile! Dans mon cas, j'ai seulement une partie de la chaîne que je veux encode, par exemple , je veux transformer my stringà my%20string. Votre solution fonctionne comme un charme pour ça!
TanguyP
A travaillé pour moi d'obtenir %20au lieu de +. Merci
Jossef Harush
21

Notez que le urllib.urlencode ne fait pas toujours l'affaire. Le problème est que certains services se soucient de l'ordre des arguments, qui est perdu lorsque vous créez le dictionnaire. Pour de tels cas, urllib.quote_plus est meilleur, comme l'a suggéré Ricky.

user411279
la source
2
Cela fonctionne bien et préserve l'ordre si vous passez une liste de tuples:>>> import urllib >>> urllib.urlencode([('name', 'brandon'), ('uid', 1000)]) 'name=brandon&uid=1000'
Brandon Rhodes
8

En Python 3, cela a fonctionné avec moi

import urllib

urllib.parse.quote(query)
Mazen Aly
la source
6

pour les futures références (ex: pour python3)

>>> import urllib.request as req
>>> query = 'eventName=theEvent&eventDescription=testDesc'
>>> req.pathname2url(query)
>>> 'eventName%3DtheEvent%26eventDescription%3DtestDesc'
nickanor
la source
1
en général, vous ne voulez que coder les valeurs par URL, ce que vous avez fait ici rendrait une requête GET invalide
Codewithcheese
La sortie pour 'c:/2 < 3'sous Windows est '///C://2%20%3C%203'. Je veux quelque chose qui ne ferait que sortir 'c:/2%20%3C%203'.
binki
3

Pour une utilisation dans des scripts / programmes qui doivent prendre en charge à la fois python 2 et 3, le module six fournit des fonctions de citation et d'urlencode:

>>> from six.moves.urllib.parse import urlencode, quote
>>> data = {'some': 'query', 'for': 'encoding'}
>>> urlencode(data)
'some=query&for=encoding'
>>> url = '/some/url/with spaces and %;!<>&'
>>> quote(url)
'/some/url/with%20spaces%20and%20%25%3B%21%3C%3E%26'
bschlueter
la source
2

Si urllib.parse.urlencode () vous donne des erreurs, essayez le module urllib3.

La syntaxe est la suivante:

import urllib3
urllib3.request.urlencode({"user" : "john" }) 
Natesh bhat
la source
1

Une autre chose qui n'a peut-être pas déjà été mentionnée est que urllib.urlencode()les valeurs vides dans le dictionnaire seront encodées en tant que chaîne Noneau lieu d'avoir ce paramètre absent. Je ne sais pas si cela est généralement souhaité ou non, mais ne correspond pas à mon cas d'utilisation, donc je dois l'utiliser quote_plus.

Joseph
la source
0

Pour Python 3 urllib3 fonctionne correctement, vous pouvez utiliser comme suit selon ses documents officiels :

import urllib3

http = urllib3.PoolManager()
response = http.request(
     'GET',
     'https://api.prylabs.net/eth/v1alpha1/beacon/attestations',
     fields={  # here fields are the query params
          'epoch': 1234,
          'pageSize': pageSize 
      } 
 )
response = attestations.data.decode('UTF-8')
cryptoKTM
la source