Як відсотково кодувати параметри URL-адреси в Python?


299

Якщо я це роблю

url = "http://example.com?p=" + urllib.quote(query)
  1. Він не кодує /до %2F(порушує нормалізацію OAuth)
  2. Він не обробляє Unicode (він кидає виняток)

Чи є краща бібліотека?


1
Це не параметри URL-адреси, FYI. Вам слід уточнити.
Джеймі Маршалл

Відповіді:


390

Пітон 2

З документів :

urllib.quote(string[, safe])

Замініть спеціальні символи в рядку, використовуючи% xx escape. Букви, цифри та символи "_.-" ніколи не цитуються. За замовчуванням ця функція призначена для цитування розділу шляху URL-адреси. Необов’язковий безпечний параметр вказує додаткові символи, які не слід цитувати - його значення за замовчуванням - '/'

Це означає, що передача "" для безпечного вирішить вашу першу проблему:

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

Про другий питанні, є помилка звіт про це тут . Мабуть, це було зафіксовано в python 3. Ви можете його обійти, кодуючи як utf8, як це:

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

До речі, подивіться на urlencode

Пітон 3

Те саме, крім заміни urllib.quoteна urllib.parse.quote.


1
Дякую, обидва працювали чудово. urlencode просто викликає quoplus багато разів у циклі, що не є правильною нормалізацією для мого завдання (oauth).
Пол Тарджан

6
spec: rfc 2396 визначає їх як зарезервовані. reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","З чим має справу urllib.quote.
Джефф Шеффілд

63
urllib.quoteпереміщено до urlib.parse.quotePython3.
Hibou57


Також у випадку кодування пошукового запиту вам, можливо, краще скористатися quo_plus: docs.python.org/3/library/… 1. Він кодує косої риски за замовчуванням 2. Він також кодує пробіли
Павло Вергеєв

174

У Python 3 urllib.quoteбуло переміщено до urllib.parse.quoteта він обробляє unicode за замовчуванням.

>>> from urllib.parse import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
>>> quote('/El Niño/')
'/El%20Ni%C3%B1o/'

2
Назва quoteдосить неясна як глобальна. Може бути , краще використовувати що - щось на зразок UrlEncode: from urllib.parse import quote as urlencode.
Люк

Зауважте, що функція, названа urlencodeв urllib.parseуже, робить щось зовсім інше, тому вам краще вибрати інше ім’я або ризикнути серйозно заплутати майбутніх читачів вашого коду.
джеймер

48

Моя відповідь схожа на відповідь Паоло.

Я думаю, що модуль requestsнабагато краще. Це засновано на urllib3. Ви можете спробувати це:

>>> from requests.utils import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'

5
requests.utils.quoteє посиланням на python quote. Дивіться джерела запиту .
Cjkjvfnby

16
requests.utils.quote- це тонка обгортка сумісності urllib.quoteдля python 2 та urllib.parse.quotepython 3
Jeff Sheffield

13

Якщо ви використовуєте django, ви можете використовувати urlquote:

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

Зауважте, що зміни в Python з моменту опублікування цієї відповіді означають, що це тепер застаріла обгортка. З вихідного коду Django 2.1 для django.utils.http:

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

2

Тут краще використовувати urlencode. Не велика різниця для одного параметра, але IMHO робить код більш зрозумілим. (Зрозуміло незрозуміло бачити функцію quote_plus! Особливо ті, що надходять від інших мов)

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

Документи

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.