Como codificar por cento parâmetros de URL em Python?

299

Se eu fizer

url = "http://example.com?p=" + urllib.quote(query)
  1. Não codifica /para %2F(quebra a normalização do OAuth)
  2. Ele não lida com Unicode (gera uma exceção)

Existe uma biblioteca melhor?

Paul Tarjan
fonte
1
Estes não são parâmetros de URL, FYI. Você deveria esclarecer.
Jamie Marshall

Respostas:

390

Python 2

Dos documentos :

urllib.quote(string[, safe])

Substitua caracteres especiais na string usando o escape% xx. Letras, dígitos e os caracteres '_.-' nunca são citados. Por padrão, essa função se destina a citar a seção de caminho da URL. O parâmetro opcional safe especifica caracteres adicionais que não devem ser citados - seu valor padrão é '/'

Isso significa que passar '' para o cofre resolverá seu primeiro problema:

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

Sobre a segunda edição, há um relatório de bug sobre isso aqui . Aparentemente, ele foi corrigido no python 3. Você pode contornar isso codificando como utf8 assim:

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

A propósito, dê uma olhada no urlencode

Python 3

O mesmo, exceto substituir urllib.quotepor urllib.parse.quote.

Nadia Alramli
fonte
1
Obrigado, ambos funcionaram muito bem. O urlencode chama apenas quoteplus muitas vezes em um loop, o que não é a normalização correta para minha tarefa (oauth).
Paul Tarjan
6
a especificação: rfc 2396 define-os como reservados. reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","É com isso que o urllib.quote está lidando.
22815 Jeffreyffffffff
63
urllib.quotemudou-se para urlib.parse.quote, desde Python3.
precisa
5
urllib.parse.quote docs
Andreas Haferburg
Além disso, no caso de codificar uma consulta de pesquisa, talvez seja melhor usar quote_plus: docs.python.org/3/library/… 1. Ele codifica barras por padrão 2. Ele também codifica espaços
Pavel Vergeev
174

No Python 3, urllib.quotefoi movido para urllib.parse.quotee lida com unicode por padrão.

>>> from urllib.parse import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
>>> quote('/El Niño/')
'/El%20Ni%C3%B1o/'
Paolo Moretti
fonte
2
O nome quoteé bastante vago como um global. Pode ser mais agradável de usar algo como urlencode: from urllib.parse import quote as urlencode.
Luc
Note-se que há uma função chamada urlencodeem urllib.parsejá que faz algo completamente diferente, então você seria melhor fora de escolher outro nome ou o risco de confundir seriamente futuros leitores do seu código.
jaymmer - Restabelece Monica
48

Minha resposta é semelhante à resposta de Paolo.

Eu acho que o módulo requestsé muito melhor. É baseado em urllib3. Você pode tentar isso:

>>> from requests.utils import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
Aminah Nuraini
fonte
5
requests.utils.quoteé um link para python quote. Veja fontes de solicitação .
Cjkjvfnby
16
requests.utils.quoteé um invólucro compatibilidade fina para urllib.quotepara python 2 e urllib.parse.quotepara python 3
Jeff Sheffield
13

Se você estiver usando django, poderá usar urlquote:

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

Observe que as alterações no Python desde que esta resposta foi publicada significam que agora é um wrapper herdado. No código-fonte do Django 2.1 para django.utils.http:

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

É melhor usar urlencodeaqui. Não há muita diferença para um único parâmetro, mas o IMHO torna o código mais claro. (Parece confuso ver uma função quote_plus! Especialmente as que vêm de outros idiomas)

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

Documentos

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
fonte