Jak urlencode kwerendę w Pythonie?

552

Próbuję urlencode ten ciąg przed przesłaniem.

queryString = 'eventName=' + evt.fields["eventName"] + '&' + 'eventDescription=' + evt.fields["eventDescription"]; 
James
źródło

Odpowiedzi:

561

Musisz przekazać swoje parametry urlencode()jako mapowanie (dict) lub sekwencję 2-krotek, takich jak:

>>> import urllib
>>> f = { 'eventName' : 'myEvent', 'eventDescription' : 'cool event'}
>>> urllib.urlencode(f)
'eventName=myEvent&eventDescription=cool+event'

Python 3 lub nowszy

Posługiwać się:

>>> urllib.parse.urlencode(f)
eventName=myEvent&eventDescription=cool+event

Zauważ, że ten sposób nie zrobić url kodowania w powszechnie używanych zmysł (spojrzenie na wyjściu). Do tego celu urllib.parse.quote_plus.

bgporter
źródło
12
„Zauważ, że urllib.urlencode nie zawsze rozwiązuje problem. Problem polega na tym, że niektóre usługi dbają o kolejność argumentów, które gubią się podczas tworzenia słownika. W takich przypadkach lepiej jest urllib.quote_plus, jak sugerował Ricky. „
Blairg23,
16
Technicznie to błąd w usługach, prawda?
holdenweb,
5
i jak to zrobić, jeśli chcesz po prostu uczynić adres URL ciągu bezpiecznym, bez budowania pełnego ciągu argumentu zapytania?
Mike 'Pomax' Kamermans
1
@ Mike'Pomax'Kamermans - patrz np stackoverflow.com/questions/12082314/... lub odpowiedź Ricky'ego na to pytanie.
bporter
1
@ bk0 wygląda na to, że twoja metoda jest ważna tylko dla słowników, a nie ciągów.
JD Gamboa
1021

Python 2

To czego szukasz to urllib.quote_plus:

>>> urllib.quote_plus('string_of_characters_like_these:$#@=?%^Q^$')
'string_of_characters_like_these%3A%24%23%40%3D%3F%25%5EQ%5E%24'

Python 3

W Pythonie 3 urllibpakiet został podzielony na mniejsze komponenty. Użyjesz urllib.parse.quote_plus(zwróć uwagę na parsemoduł potomny)

import urllib.parse
urllib.parse.quote_plus(...)
Ricky
źródło
4
Dzięki! W moim przypadku muszę jednak wprowadzić:import urllib.parse ... urllib.parse.quote_plus(query)
ivkremer
3
bardzo dobrze, ale dlaczego nie używał kodu Unicode? Jeśli ciąg adresu URL to Unicode, muszę go zakodować na UTF-8. Czy jest jakiś inny sposób?
Karl Doenitz
7
Działa to świetnie, ale nie mogłem uzyskać dostępu do niektórych usług online (REST), dopóki nie dodałem tego parametru safe = '; /?: @ & = + $,'
rovyko
Próbowałem tego w Pythonie 3, ale nie byłem w stanie: stackoverflow.com/questions/40557606/…
amfibia
1
python3 -c "import urllib.parse, sys; print(urllib.parse.quote_plus(sys.argv[1])) "string to encode"dla jednego linijki w wierszu poleceń
Amos Joshua
52

Wypróbuj żądania zamiast urllib i nie musisz przejmować się urlencode!

import requests
requests.get('http://youraddress.com', params=evt.fields)

EDYTOWAĆ:

Jeśli potrzebujesz uporządkowanych par nazwa-wartość lub wielu wartości dla nazwy, ustaw następujące parametry:

params=[('name1','value11'), ('name1','value12'), ('name2','value21'), ...]

zamiast używać słownika.

Barney
źródło
5
Nie rozwiązuje to problemu zamawiania par nazwa-wartość, wymaga to również pozwolenia na instalację zewnętrznych bibliotek, które mogą nie być wykonalne dla projektu.
dreftymac,
Opublikowałem minimalny kod, który działałby dla OP. OP nie zażądał zamówionych par, ale jest to również wykonalne, zobacz moją aktualizację.
Barney
@dreftymac: dotyczy to zamawiania (chociaż nie było to częścią pytania), przeczytaj moją zaktualizowaną odpowiedź.
Barney,
36

Kontekst

  • Python (wersja 2.7.2)

Problem

  • Chcesz wygenerować zakodowany ciąg zapytania.
  • Masz słownik lub obiekt zawierający pary nazwa-wartość.
  • Chcesz mieć możliwość kontrolowania kolejności wyjściowej par nazwa-wartość.

Rozwiązanie

  • urllib.urlencode
  • urllib.quote_plus

Pułapki

Przykład

Poniżej znajduje się kompletne rozwiązanie, w tym sposób radzenia sobie z niektórymi pułapkami.

### ********************
## init python (version 2.7.2 )
import urllib

### ********************
## first setup a dictionary of name-value pairs
dict_name_value_pairs = {
  "bravo"   : "True != False",
  "alpha"   : "http://www.example.com",
  "charlie" : "hello world",
  "delta"   : "1234567 !@#$%^&*",
  "echo"    : "[email protected]",
  }

### ********************
## setup an exact ordering for the name-value pairs
ary_ordered_names = []
ary_ordered_names.append('alpha')
ary_ordered_names.append('bravo')
ary_ordered_names.append('charlie')
ary_ordered_names.append('delta')
ary_ordered_names.append('echo')

### ********************
## show the output results
if('NO we DO NOT care about the ordering of name-value pairs'):
  queryString  = urllib.urlencode(dict_name_value_pairs)
  print queryString 
  """
  echo=user%40example.com&bravo=True+%21%3D+False&delta=1234567+%21%40%23%24%25%5E%26%2A&charlie=hello+world&alpha=http%3A%2F%2Fwww.example.com
  """

if('YES we DO care about the ordering of name-value pairs'):
  queryString  = "&".join( [ item+'='+urllib.quote_plus(dict_name_value_pairs[item]) for item in ary_ordered_names ] )
  print queryString
  """
  alpha=http%3A%2F%2Fwww.example.com&bravo=True+%21%3D+False&charlie=hello+world&delta=1234567+%21%40%23%24%25%5E%26%2A&echo=user%40example.com
  """ 
dreftymac
źródło
23

Spróbuj tego:

urllib.pathname2url(stringToURLEncode)

urlencodenie będzie działać, ponieważ działa tylko w słownikach. quote_plusnie wygenerował prawidłowego wyniku.

Charlie
źródło
To bardzo pomocne! W moim przypadku, mam tylko część napisu, że chcę zakodować URL, na przykład chcę, aby przekształcić my stringsię my%20string. Twoje rozwiązanie działa jak urok!
TanguyP
Pracował dla mnie %20zamiast +. Dzięki
Jossef Harush
21

Zauważ, że urllib.urlencode nie zawsze załatwia sprawę. Problem polega na tym, że niektóre usługi dbają o kolejność argumentów, które gubią się podczas tworzenia słownika. W takich przypadkach lepiej jest urllib.quote_plus, jak sugerował Ricky.

użytkownik 411279
źródło
2
Działa dobrze i zachowuje porządek, jeśli przejdziesz listę krotek:>>> import urllib >>> urllib.urlencode([('name', 'brandon'), ('uid', 1000)]) 'name=brandon&uid=1000'
Brandon Rhodes
8

W Pythonie 3 to zadziałało ze mną

import urllib

urllib.parse.quote(query)
Mazen Aly
źródło
6

dla przyszłych odniesień (np .: dla python3)

>>> import urllib.request as req
>>> query = 'eventName=theEvent&eventDescription=testDesc'
>>> req.pathname2url(query)
>>> 'eventName%3DtheEvent%26eventDescription%3DtestDesc'
nickanor
źródło
1
zazwyczaj chcesz tylko zakodować adresy URL, to, co tu zrobiłeś, spowodowałoby nieprawidłowe zapytanie GET
Codewithcheese
Dane wyjściowe dla 'c:/2 < 3'systemu Windows to '///C://2%20%3C%203'. Chcę czegoś, co po prostu wyjdzie 'c:/2%20%3C%203'.
binki
3

Do użytku w skryptach / programach, które muszą obsługiwać zarówno Python 2, jak i 3, moduł sześciu udostępnia funkcje cytowania i urlencode:

>>> from six.moves.urllib.parse import urlencode, quote
>>> data = {'some': 'query', 'for': 'encoding'}
>>> urlencode(data)
'some=query&for=encoding'
>>> url = '/some/url/with spaces and %;!<>&'
>>> quote(url)
'/some/url/with%20spaces%20and%20%25%3B%21%3C%3E%26'
bschlueter
źródło
2

Jeśli funkcja urllib.parse.urlencode () powoduje błędy, wypróbuj moduł urllib3.

Składnia jest następująca:

import urllib3
urllib3.request.urlencode({"user" : "john" }) 
Natesh bhat
źródło
1

Inną rzeczą, o której jeszcze nie wspomniano, jest urllib.urlencode()zakodowanie pustych wartości w słowniku jako ciągu Nonezamiast braku tego parametru. Nie wiem, czy jest to zwykle pożądane, czy nie, ale nie pasuje do mojego przypadku użycia, dlatego muszę go użyć quote_plus.

Joseph
źródło
0

Dla urllib3 w Pythonie 3 działa poprawnie, możesz użyć następujących instrukcji zgodnie z oficjalnymi dokumentami :

import urllib3

http = urllib3.PoolManager()
response = http.request(
     'GET',
     'https://api.prylabs.net/eth/v1alpha1/beacon/attestations',
     fields={  # here fields are the query params
          'epoch': 1234,
          'pageSize': pageSize 
      } 
 )
response = attestations.data.decode('UTF-8')
cryptoKTM
źródło