Como urlencode uma querystring em Python?

552

Estou tentando codificar esta cadeia de caracteres antes de enviar.

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

Respostas:

561

Você precisa passar seus parâmetros para urlencode()um mapeamento (dict) ou uma sequência de duas tuplas, como:

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

Python 3 ou superior

Usar:

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

Note que isso não faz url codificação no sentido comumente usado (veja a saída). Para esse uso urllib.parse.quote_plus.

bgporter
fonte
12
"Observe que o urllib.urlencode nem sempre funciona. O problema é que alguns serviços se preocupam com a ordem dos argumentos, que se perde quando você cria o dicionário. Para esses casos, o urllib.quote_plus é melhor, como sugeriu Ricky. "
precisa saber é o seguinte
16
Tecnicamente, isso é um bug nos serviços, não é?
precisa saber é o seguinte
5
e como fazer isso se você apenas deseja tornar um URL de string seguro, sem criar uma string de argumento de consulta completa?
Mike 'Pomax' Kamermans
1
@ Mike'Pomax'Kamermans - veja, por exemplo, stackoverflow.com/questions/12082314/… ou a resposta de Ricky para esta pergunta.
bgporter
1
@ bk0 parece que seu método é válido apenas para dicionários, e não para strings.
JD Gamboa
1021

Python 2

O que você está procurando é 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

No Python 3, o urllibpacote foi dividido em componentes menores. Você usará urllib.parse.quote_plus(observe o parsemódulo filho)

import urllib.parse
urllib.parse.quote_plus(...)
Ricky
fonte
4
Obrigado! No meu caso, no entanto, eu preciso colocar:import urllib.parse ... urllib.parse.quote_plus(query)
ivkremer 02/09
3
muito bom, mas por que não é usado para Unicode? Se a string de URL é Unicode, devo codificá-la para UTF-8. Existe alguma outra maneira de fazer isso?
Karl Doenitz
7
Isso funciona muito bem, mas eu não podia acessar alguns serviços online (REST) até que eu adicionei este parâmetro safe = '; /: @ & = + $,'
rovyko
Eu tentei isso no Python 3, mas não foi capaz de: stackoverflow.com/questions/40557606/… #
amphibient
1
python3 -c "import urllib.parse, sys; print(urllib.parse.quote_plus(sys.argv[1])) "string to encode"para um um forro na linha de comando
Amos Joshua
52

Tente solicitações em vez de urllib e você não precisa se preocupar com o urlencode!

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

EDITAR:

Se você precisar de pares nome-valor ou vários valores ordenados para um nome, defina os parâmetros como:

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

em vez de usar um dicionário.

Barney
fonte
5
Isso não resolve o problema de ordenar os pares nome-valor, também requer a permissão para instalar bibliotecas externas que podem não ser factíveis para o projeto.
precisa saber é o seguinte
Publiquei o código mínimo que funcionaria para o OP. O OP não solicitou pares ordenados, no entanto, também é possível, veja minha atualização.
Barney
@refrefmac: trata da encomenda (embora não faça parte da pergunta), leia minha resposta atualizada.
Barney #
36

Contexto

  • Python (versão 2.7.2)

Problema

  • Você deseja gerar uma string de consulta codificada em url.
  • Você tem um dicionário ou objeto que contém os pares nome-valor.
  • Você deseja controlar a ordem de saída dos pares nome-valor.

Solução

  • urllib.urlencode
  • urllib.quote_plus

Armadilhas

Exemplo

A seguir, é apresentada uma solução completa, incluindo como lidar com algumas armadilhas.

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

Tente o seguinte:

urllib.pathname2url(stringToURLEncode)

urlencodenão funcionará porque funciona apenas em dicionários. quote_plusnão produziu a saída correta.

Charlie
fonte
Isso é realmente útil! No meu caso, eu só tenho uma parte da cadeia de caracteres que eu quero URL-codificar, por exemplo, eu quero transformar my stringa my%20string. Sua solução funciona como um encanto para isso!
TanguyP
Trabalhou para eu conseguir, em %20vez de +. Obrigado
Jossef Harush
21

Observe que o urllib.urlencode nem sempre faz o truque. O problema é que alguns serviços se preocupam com a ordem dos argumentos, que são perdidos quando você cria o dicionário. Nesses casos, o urllib.quote_plus é melhor, como sugeriu Ricky.

user411279
fonte
2
Funciona bem e preserva a ordem se você passar uma lista de tuplas:>>> import urllib >>> urllib.urlencode([('name', 'brandon'), ('uid', 1000)]) 'name=brandon&uid=1000'
Brandon Rhodes
8

No Python 3, isso funcionou comigo

import urllib

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

para referências futuras (ex: para python3)

>>> import urllib.request as req
>>> query = 'eventName=theEvent&eventDescription=testDesc'
>>> req.pathname2url(query)
>>> 'eventName%3DtheEvent%26eventDescription%3DtestDesc'
nickanor
fonte
1
Normalmente, você só quer codificar url os valores, o que você fez aqui faria uma consulta GET inválido
Codewithcheese
A saída para 'c:/2 < 3'no Windows é '///C://2%20%3C%203'. Eu quero algo que acabaria de sair 'c:/2%20%3C%203'.
binki
3

Para uso em scripts / programas que precisam oferecer suporte ao python 2 e 3, o módulo seis fornece funções de cotação e 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
fonte
2

Se o urllib.parse.urlencode () estiver apresentando erros, tente o módulo urllib3.

A sintaxe é a seguinte:

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

Outra coisa que pode não ter sido mencionada já é que urllib.urlencode()codificará valores vazios no dicionário como a string em Nonevez de ter esse parâmetro ausente. Não sei se isso é normalmente desejado ou não, mas não se encaixa no meu caso de uso, portanto, tenho que usá-lo quote_plus.

Joseph
fonte
0

Para o Python 3, o urllib3 funciona corretamente, você pode usar como segue os documentos oficiais :

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
fonte