Bagaimana cara persen-encode parameter URL di Python?

299

Jika aku melakukan

url = "http://example.com?p=" + urllib.quote(query)
  1. Itu tidak encode /ke %2F(istirahat OAuth normalisasi)
  2. Itu tidak menangani Unicode (ini melempar pengecualian)

Apakah ada perpustakaan yang lebih baik?

Paul Tarjan
sumber
1
Ini bukan parameter URL, FYI. Anda harus mengklarifikasi.
Jamie Marshall

Jawaban:

390

Python 2

Dari dokumen :

urllib.quote(string[, safe])

Ganti karakter khusus dalam string menggunakan% xx escape. Huruf, angka, dan karakter '_.-' tidak pernah dikutip. Secara default, fungsi ini dimaksudkan untuk mengutip bagian jalur URL. Parameter aman opsional menentukan karakter tambahan yang tidak boleh dikutip - nilai defaultnya adalah '/'

Itu berarti melewati '' untuk aman akan menyelesaikan masalah pertama Anda:

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

Tentang masalah kedua, ada laporan bug di sini . Rupanya itu diperbaiki dalam python 3. Anda dapat mengatasinya dengan pengkodean sebagai utf8 seperti ini:

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

Omong-omong lihat urlencode

Python 3

Sama, kecuali ganti urllib.quotedengan urllib.parse.quote.

Nadia Alramli
sumber
1
Terima kasih, keduanya bekerja dengan baik. urlencode hanya memanggil quoteplus berkali-kali dalam satu lingkaran, yang bukan merupakan normalisasi yang benar untuk tugas saya (oauth).
Paul Tarjan
6
spec: rfc 2396 mendefinisikan ini sebagai cadangan. reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","Inilah yang berurusan dengan urllib.quote.
Jeff Sheffield
63
urllib.quotedipindahkan ke urlib.parse.quote, sejak Python3.
Hibou57
5
urllib.parse.quote docs
Andreas Haferburg
Juga, dalam hal menyandikan kueri pencarian, Anda mungkin lebih baik menggunakan quote_plus: docs.python.org/3/library/… 1. Ini menyandikan garis miring secara default 2. Juga menyandikan spasi
Pavel Vergeev
174

Dalam Python 3, urllib.quotetelah dipindahkan ke urllib.parse.quotedan menangani unicode secara default.

>>> from urllib.parse import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
>>> quote('/El Niño/')
'/El%20Ni%C3%B1o/'
Paolo Moretti
sumber
2
Nama quoteitu agak kabur sebagai global. Mungkin lebih baik untuk menggunakan sesuatu seperti urlencode: from urllib.parse import quote as urlencode.
Luc
Perhatikan bahwa ada fungsi yang sudah ada urlencodedi dalam urllib.parseyang melakukan sesuatu yang sama sekali berbeda, jadi sebaiknya Anda memilih nama lain atau berisiko serius membingungkan pembaca kode Anda di masa mendatang.
jaymmer
48

Jawaban saya mirip dengan jawaban Paolo.

Saya pikir modul requestsjauh lebih baik. Ini berdasarkan urllib3. Anda dapat mencoba ini:

>>> from requests.utils import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
Aminah Nuraini
sumber
5
requests.utils.quoteadalah tautan ke python quote. Lihat sumber permintaan .
Cjkjvfnby
16
requests.utils.quoteadalah pembungkus kompatibilitas tipis untuk urllib.quoteuntuk python 2 dan urllib.parse.quoteuntuk python 3
Jeff Sheffield
13

Jika Anda menggunakan Django, Anda dapat menggunakan urlquote:

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

Perhatikan bahwa perubahan pada Python sejak jawaban ini dipublikasikan berarti bahwa ini sekarang adalah pembungkus warisan. Dari kode sumber Django 2.1 untuk django.utils.http:

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

Lebih baik digunakan di urlencodesini. Tidak banyak perbedaan untuk parameter tunggal tetapi IMHO membuat kode lebih jelas. (Sepertinya membingungkan melihat fungsi quote_plus! Terutama yang berasal dari negara lain)

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

Documents

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
sumber