¿Cómo urlencode una cadena de consulta en Python?

552

Estoy tratando de codificar esta cadena antes de enviarla.

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

Respuestas:

561

Debe pasar sus parámetros urlencode()como una asignación (dict) o una secuencia de 2 tuplas, como:

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

Python 3 o superior

Utilizar:

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

Tenga en cuenta que esto no hace la codificación de URL en el sentido comúnmente utilizado (mire la salida). Para ese uso urllib.parse.quote_plus.

bgporter
fuente
12
"Tenga en cuenta que urllib.urlencode no siempre funciona. El problema es que algunos servicios se preocupan por el orden de los argumentos, que se pierden al crear el diccionario. Para tales casos, urllib.quote_plus es mejor, como sugirió Ricky. "
Blairg23
16
Técnicamente, eso es un error en los servicios, ¿no?
holdenweb
55
y ¿cómo podría uno hacer esto si solo desea que una URL de cadena sea segura, sin construir una cadena de argumento de consulta completa?
Mike 'Pomax' Kamermans
1
@ Mike'Pomax'Kamermans: consulte, por ejemplo, stackoverflow.com/questions/12082314/… o la respuesta de Ricky a esta pregunta.
bgporter
1
@ bk0 parece que su método solo es válido para diccionarios y no para cadenas.
JD Gamboa
1021

Python 2

Lo que estás buscando es 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, el urllibpaquete se ha dividido en componentes más pequeños. Usarás urllib.parse.quote_plus(ten en cuenta el parsemódulo secundario)

import urllib.parse
urllib.parse.quote_plus(...)
Ricky
fuente
44
¡Gracias! En mi caso, sin embargo tengo que poner:import urllib.parse ... urllib.parse.quote_plus(query)
ivkremer
3
muy bueno, pero ¿por qué no se usa para Unicode? Si la cadena de url es Unicode, debo codificarla en UTF-8. ¿Hay alguna otra forma de hacerlo?
Karl Doenitz
77
Esto funciona muy bien, pero no pude acceder a algunos servicios en línea (REST) ​​hasta que agregué este parámetro safe = '; /?: @ & = + $,'
rovyko
Lo intenté en Python 3 pero no pude: stackoverflow.com/questions/40557606/…
anfibio
1
python3 -c "import urllib.parse, sys; print(urllib.parse.quote_plus(sys.argv[1])) "string to encode"para un trazador de líneas en la línea de comando
Amos Joshua
52

¡Pruebe las solicitudes en lugar de urllib y no necesita molestarse con urlencode!

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

EDITAR:

Si necesita pares ordenados de nombre-valor o valores múltiples para un nombre, configure los parámetros de la siguiente manera:

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

en lugar de usar un diccionario.

Barney
fuente
55
Esto no resuelve el problema de ordenar los pares de nombre y valor, también requiere el permiso para instalar bibliotecas externas que podrían no ser factibles para el proyecto.
dreftymac
Publiqué el código mínimo que funcionaría para el OP. El OP no solicitó pares ordenados, sin embargo, también es factible, consulte mi actualización.
Barney
@dreftymac: esto aborda el pedido (aunque no era parte de la pregunta), lea mi respuesta actualizada.
Barney
36

Contexto

  • Python (versión 2.7.2)

Problema

  • Desea generar una cadena de consulta urlencoded.
  • Tiene un diccionario u objeto que contiene los pares nombre-valor.
  • Desea poder controlar el orden de salida de los pares nombre-valor.

Solución

  • urllib.urlencode
  • urllib.quote_plus

Trampas

Ejemplo

La siguiente es una solución completa, que incluye cómo lidiar con algunas dificultades.

### ********************
## 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
fuente
23

Prueba esto:

urllib.pathname2url(stringToURLEncode)

urlencodeno funcionará porque solo funciona en diccionarios. quote_plusno produjo la salida correcta.

Charlie
fuente
Eso es realmente útil! En mi caso, tengo solamente una porción de cadena que quiero cifrar la URL de, por ejemplo, quiero transformar my stringa my%20string. ¡Su solución funciona de maravilla para eso!
TanguyP
Trabajó para mí para obtener en %20lugar de +. Gracias
Jossef Harush
21

Tenga en cuenta que el urllib.urlencode no siempre funciona. El problema es que algunos servicios se preocupan por el orden de los argumentos, que se pierden al crear el diccionario. Para tales casos, urllib.quote_plus es mejor, como sugirió Ricky.

usuario411279
fuente
2
Funciona bien y conserva el orden si pasa una lista de tuplas:>>> import urllib >>> urllib.urlencode([('name', 'brandon'), ('uid', 1000)]) 'name=brandon&uid=1000'
Brandon Rhodes
8

En Python 3, esto funcionó conmigo

import urllib

urllib.parse.quote(query)
Mazen Aly
fuente
6

para futuras referencias (ej .: para python3)

>>> import urllib.request as req
>>> query = 'eventName=theEvent&eventDescription=testDesc'
>>> req.pathname2url(query)
>>> 'eventName%3DtheEvent%26eventDescription%3DtestDesc'
nickanor
fuente
1
por lo general, solo desea codificar los valores de la URL, lo que ha hecho aquí haría una consulta GET no válida
Codewithcheese
El resultado para 'c:/2 < 3'en Windows es '///C://2%20%3C%203'. Quiero algo que solo salga 'c:/2%20%3C%203'.
binki
3

Para su uso en scripts / programas que necesitan ser compatibles con python 2 y 3, el módulo seis proporciona funciones de comillas y códigos de urlen:

>>> 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
fuente
2

Si urllib.parse.urlencode () le está dando errores, intente con el módulo urllib3.

La sintaxis es la siguiente:

import urllib3
urllib3.request.urlencode({"user" : "john" }) 
Natesh Bhat
fuente
1

Otra cosa que podría no haberse mencionado ya es que urllib.urlencode()codificará valores vacíos en el diccionario como la cadena en Nonelugar de tener ese parámetro como ausente. No sé si esto normalmente se desea o no, pero no se ajusta a mi caso de uso, por lo tanto, tengo que usarlo quote_plus.

José
fuente
0

Para Python 3, urllib3 funciona correctamente, puede usar lo siguiente según sus documentos oficiales :

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
fuente