Wie werden URL-Parameter in Python prozentual codiert?

299

Wenn ich mache

url = "http://example.com?p=" + urllib.quote(query)
  1. Es codiert nicht /zu %2F(unterbricht die OAuth-Normalisierung)
  2. Unicode wird nicht behandelt (es wird eine Ausnahme ausgelöst)

Gibt es eine bessere Bibliothek?

Paul Tarjan
quelle
1
Dies sind keine URL-Parameter, FYI. Sie sollten klarstellen.
Jamie Marshall

Antworten:

390

Python 2

Aus den Dokumenten :

urllib.quote(string[, safe])

Ersetzen Sie Sonderzeichen in der Zeichenfolge mit dem Escapezeichen% xx. Buchstaben, Ziffern und die Zeichen '_.-' werden niemals in Anführungszeichen gesetzt. Standardmäßig dient diese Funktion zum Zitieren des Pfadabschnitts der URL. Der optionale Parameter safe gibt zusätzliche Zeichen an, die nicht in Anführungszeichen gesetzt werden sollen. Der Standardwert ist '/'.

Das bedeutet, dass das sichere Bestehen von '' Ihr erstes Problem löst:

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

Über das zweite Problem gibt es hier einen Fehlerbericht . Anscheinend wurde es in Python 3 behoben. Sie können es umgehen, indem Sie es wie folgt als utf8 codieren:

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

Schauen Sie sich übrigens urlencode an

Python 3

Das gleiche, nur ersetzen urllib.quotemit urllib.parse.quote.

Nadia Alramli
quelle
1
Danke, beide haben super funktioniert. urlencode ruft nur viele Male quoteplus in einer Schleife auf, was nicht die richtige Normalisierung für meine Aufgabe ist (oauth).
Paul Tarjan
6
Die Spezifikation: rfc 2396 definiert diese als reserviert. reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","Damit befasst sich urllib.quote.
Jeff Sheffield
63
urllib.quoteumgezogen urlib.parse.quote, seit Python3.
Hibou57
5
urllib.parse.quote docs
Andreas Haferburg
Wenn Sie eine Suchabfrage codieren, ist es möglicherweise besser, quote_plus zu verwenden: docs.python.org/3/library/… 1. Standardmäßig werden Schrägstriche codiert. 2. Außerdem werden Leerzeichen codiert
Pavel Vergeev
174

In Python 3 urllib.quotewurde nach verschoben urllib.parse.quoteund es verarbeitet standardmäßig Unicode.

>>> from urllib.parse import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
>>> quote('/El Niño/')
'/El%20Ni%C3%B1o/'
Paolo Moretti
quelle
2
Der Name quoteist als global eher vage. Es könnte schöner sein, so etwas wie Urlencode zu verwenden : from urllib.parse import quote as urlencode.
Luc
Beachten Sie, dass es eine Funktion mit dem Namen ist urlencodein urllib.parsebereits , dass etwas ganz anderes tut, so dass Sie besser sein würde aus anderen Namen Kommissionierung oder das Risiko ernst zukünftige Leser Ihres Codes verwirrend.
jaymmer - Monica
48

Meine Antwort ähnelt der Antwort von Paolo.

Ich denke Modul requestsist viel besser. Es basiert auf urllib3. Sie können dies versuchen:

>>> from requests.utils import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
Aminah Nuraini
quelle
5
requests.utils.quoteist Link zu Python quote. Siehe Anforderungsquellen .
Cjkjvfnby
16
requests.utils.quoteist ein dünner Kompatibilitäts-Wrapper urllib.quotefür Python 2 und urllib.parse.quotefür Python 3
Jeff Sheffield
13

Wenn Sie Django verwenden, können Sie urlquote verwenden:

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

Beachten Sie, dass Änderungen an Python seit Veröffentlichung dieser Antwort bedeuten, dass dies jetzt ein Legacy-Wrapper ist. Aus dem Django 2.1-Quellcode für django.utils.http:

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

Es ist besser, urlencodehier zu verwenden . Kein großer Unterschied für einzelne Parameter, aber IMHO macht den Code klarer. (Es sieht verwirrend aus, eine Funktion zu sehen quote_plus! Besonders die, die aus anderen Sprachen stammen)

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

Docs

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
quelle