2012-05-26 42 views
6

Estoy tratando de construir una url para que pueda enviar una solicitud de get a ella usando el módulo urllib.Construir cadena de consulta usando urlencode python

Supongamos que mi final_url debe ser

url = "www.example.com/find.php?data=http%3A%2F%2Fwww.stackoverflow.com&search=Generate+value" 

Ahora para lograr este Probé la siguiente manera:

>>> initial_url = "http://www.stackoverflow.com" 
>>> search = "Generate+value" 
>>> params = {"data":initial_url,"search":search} 
>>> query_string = urllib.urlencode(params) 
>>> query_string 
'search=Generate%2Bvalue&data=http%3A%2F%2Fwww.stackoverflow.com' 

Ahora bien, si se compara mi query_string con el formato de final_url Puede observadores dos cosas

1) El orden de los params se invierte en lugar de data=()&search= es search=()&data=

2) urlencode también codifica la + en Generate+value

Creo que el primer cambio se debe al comportamiento aleatorio del diccionario. Entonces, pensé en usar OrderedDict to reverse the dictionary. Como, estoy usando python 2.6.5 hice

pip install ordereddict 

Pero no soy capaz de utilizarlo en mi código cuando intento

>>> od = OrderedDict((('a', 'first'), ('b', 'second'))) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'OrderedDict' is not defined 

lo tanto, mi pregunta es ¿cuál es la forma correcta de utilizar OrderedDict en Python 2.6.5 y cómo hago urlencode ignora el + en Generate+value.

Además, este es el enfoque correcto para compilar URL.

Respuesta

15

No debe preocuparse por la codificación de + que debe restaurarse en el servidor después de desempañar la url. El orden de los parámetros nombrados tampoco debería importar.

Considerando OrderedDict, no es de Python construido en Usted debe importarlo de collections:.

from urllib import urlencode, quote 
# from urllib.parse import urlencode # python3 
from collections import OrderedDict 

initial_url = "http://www.stackoverflow.com" 
search = "Generate+value" 
query_string = urlencode(OrderedDict(data=initial_url,search=search)) 

si su pitón es demasiado viejo y no tiene OrderedDict en el módulo collections, utilice:

encoded = "&".join("%s=%s" % (key, quote(parameters[key], safe="+")) 
    for key in ordered(parameters.keys())) 

De todos modos, el orden de los parámetros no debería importar.

Observe el parámetro safe de quote. Impide que se escape +, pero significa que el servidor interpretará Generate+value como Generate value. Puede escaparse manualmente + escribiendo %2B y marcando % como char seguro:

+0

Intenté 'de colecciones import OrderedDict' pero ahora estoy obteniendo' ImportError: no puedo importar el nombre OrderedDict'. Estoy usando python '2.6.5' – RanRag

+0

Debería estar disponible desde pyton 2.4. ¿Qué obtendrás si ejecutas 'colecciones de importación'? –

+0

Puedo importar correctamente la colección, no se produce ningún error. Pensé que 'OrderedDict' se introdujo desde python 2.7 en adelante. – RanRag

3

En primer lugar, el orden de los parámetros en una solicitud http debe ser completamente irrelevante. Si no es así, la biblioteca de análisis en el otro lado está haciendo algo mal.

En segundo lugar, por supuesto, el + está codificado. + se usa como marcador de posición para un espacio en una url codificada, por lo que si su cadena raw contiene +, debe escaparse.urlencode espera una cadena no codificada, no se puede pasar una cadena que ya está codificada.

+0

Gracias, tienes razón. No revisé antes de preguntar mi error. – RanRag

0

Algunos comentarios sobre la pregunta y otro responde:

  1. Si desea preservar el orden con urllib.urlencode, presentan una secuencia ordenada de k/v pares en lugar de mapeo (dict). cuando pasa en un dict, urlencode simplemente llama al foo.items() para obtener una secuencia iterable.

# urllib.urlencode accepts a mapping or sequence # the output of this can vary, because `items()` is called on the dict urllib.urlencode({"data": initial_url,"search": search}) # the output of this will not vary urllib.urlencode((("data", initial_url), ("search", search)))

también puede pasar en un argumento doseq secondard para ajustar cómo los valores iterables se manejan.

  1. El orden de los parámetros no es irrelevante. tomar estas dos direcciones URL, por ejemplo:

    https://example.com?foo=bar&bar=foo https://example.com?bar=foo&foo=bar

    Un servidor HTTP debe tener en cuenta el orden de estos parámetros irrelevantes, sino una función diseñada para comparar las direcciones URL no lo haría. Para comparar urls de forma segura, estos parámetros deberían ser ordenados.

    Sin embargo, consideran claves duplicadas:

    https://example.com?foo=3&foo=2&foo=1

Las especificaciones de URI soportan claves duplicadas, pero no se ocupan de precedencia o pedido.

en una aplicación dada, estos podrían cada desencadenan diferentes resultados y sean válidas, así:

https://example.com?foo=1&foo=2&foo=3 
https://example.com?foo=1&foo=3&foo=2 
https://example.com?foo=2&foo=3&foo=1 
https://example.com?foo=2&foo=1&foo=3 
https://example.com?foo=3&foo=1&foo=2 
https://example.com?foo=3&foo=2&foo=1 
  1. El + es un carácter reservado que representa un espacio en una forma urlencoded (vs %20 para parte de el camino). urllib.urlencode escapa usando urllib.quote_plus(), no urllib.quote(). El PO más probable es que solo quería hacer esto:

initial_url = "http://www.stackoverflow.com" search = "Generate value" urllib.urlencode((("data", initial_url), ("search", search)))

que produce:

data=http%3A%2F%2Fwww.stackoverflow.com&search=Generate+value

como la salida.

Cuestiones relacionadas