Jak kodować procentowo parametry URL w Pythonie?

299

Jeśli zrobię

url = "http://example.com?p=" + urllib.quote(query)
  1. To nie koduje /się %2F(łamie OAuth normalizacja)
  2. Nie obsługuje Unicode (zgłasza wyjątek)

Czy jest lepsza biblioteka?

Paul Tarjan
źródło
1
To nie są parametry adresu URL, FYI. Powinieneś to wyjaśnić.
Jamie Marshall,

Odpowiedzi:

390

Python 2

Z dokumentów :

urllib.quote(string[, safe])

Zamień znaki specjalne w ciągu za pomocą znaku ucieczki% xx. Litery, cyfry i znaki „_.-” nigdy nie są cytowane. Domyślnie ta funkcja służy do cytowania sekcji ścieżki adresu URL. Opcjonalny bezpieczny parametr określa dodatkowe znaki, które nie powinny być cytowane - jego wartość domyślna to „/”

Oznacza to, że podanie „dla bezpieczeństwa” rozwiąże Twój pierwszy problem:

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

O drugiej kwestii, istnieje raport o błędzie o tym tutaj . Najwyraźniej zostało to naprawione w Pythonie 3. Możesz to obejść, kodując jako utf8 w następujący sposób:

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

Przy okazji spójrz na urlencode

Python 3

To samo, z wyjątkiem zastąpienia urllib.quoteprzez urllib.parse.quote.

Nadia Alramli
źródło
1
Dzięki wam oboje działali świetnie. urlencode po prostu wywołuje wielokrotnie quoteplus w pętli, co nie jest prawidłową normalizacją dla mojego zadania (oauth).
Paul Tarjan
6
specyfikacja: rfc 2396 definiuje je jako zastrzeżone. Z reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","tym ma do czynienia urllib.quote.
Jeff Sheffield,
63
urllib.quoteprzeniósł się do urlib.parse.quote, ponieważ Python3.
Hibou57
5
urllib.parse.quote docs
Andreas Haferburg
Ponadto, w przypadku kodowania zapytania wyszukiwania, lepiej użyć quote_plus: docs.python.org/3/library/… 1. Domyślnie koduje ukośniki 2. Koduje również spacje
Pavel Vergeev
174

W Pythonie 3 urllib.quotezostał przeniesiony urllib.parse.quotei domyślnie obsługuje Unicode.

>>> from urllib.parse import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
>>> quote('/El Niño/')
'/El%20Ni%C3%B1o/'
Paolo Moretti
źródło
2
Nazwa quotejest raczej ogólnikowa. To może być ładniejszy użyć czegoś jak urlencode: from urllib.parse import quote as urlencode.
Luc
Należy pamiętać, że jest to funkcja o nazwie urlencodew urllib.parsejuż, że robi coś zupełnie innego, więc byłbyś lepiej wybierając inną nazwę lub ryzyko poważnie mylące przyszłych czytelników kodzie.
jaymmer - Przywróć Monikę
48

Moja odpowiedź jest podobna do odpowiedzi Paolo.

Myślę, że moduł requestsjest znacznie lepszy. Opiera się na urllib3. Możesz spróbować:

>>> from requests.utils import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
Aminah Nuraini
źródło
5
requests.utils.quoteto link do Pythona quote. Zobacz źródła zapytań .
Cjkjvfnby
16
requests.utils.quotejest cienkim opakowaniem kompatybilności urllib.quotedla Pythona 2 i urllib.parse.quotePythona 3
Jeff Sheffield,
13

Jeśli używasz django, możesz użyć urlquote:

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

Zauważ, że zmiany w Pythonie od czasu opublikowania tej odpowiedzi oznaczają, że jest to teraz starsze opakowanie. Z kodu źródłowego Django 2.1 dla django.utils.http:

A legacy compatibility wrapper to Python's urllib.parse.quote() function.
(was used for unicode handling on Python 2)
Rick Westera
źródło
2

Lepiej jest użyć urlencodetutaj. Niewielka różnica dla pojedynczego parametru, ale IMHO sprawia, że ​​kod jest wyraźniejszy. (Wygląda na mylące, gdy widzę funkcję quote_plus! Szczególnie osoby pochodzące z innych języków)

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

Dokumenty

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
źródło