Bagaimana cara urlencode querystring dengan Python?

552

Saya mencoba urlencode string ini sebelum saya kirim.

queryString = 'eventName=' + evt.fields["eventName"] + '&' + 'eventDescription=' + evt.fields["eventDescription"]; 
James
sumber

Jawaban:

561

Anda perlu memasukkan parameter Anda urlencode()sebagai pemetaan (dict), atau urutan 2-tupel, seperti:

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

Python 3 atau lebih tinggi

Menggunakan:

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

Perhatikan bahwa ini tidak melakukan penyandian url dalam arti yang umum digunakan (lihat outputnya). Untuk itu gunakan urllib.parse.quote_plus.

bgporter
sumber
12
"Perhatikan bahwa urllib.urlencode tidak selalu berhasil. Masalahnya adalah beberapa layanan peduli dengan urutan argumen, yang hilang ketika Anda membuat kamus. Untuk kasus seperti itu, urllib.quote_plus lebih baik, seperti yang disarankan Ricky. "
Blairg23
16
Secara teknis, itu bug dalam layanan, bukan?
holdenweb
5
dan bagaimana orang melakukan ini jika Anda hanya ingin membuat URL string aman, tanpa membuat string argumen kueri lengkap?
Mike 'Pomax' Kamermans
1
@ Mike'Pomax'Kamermans - lihat misalnya stackoverflow.com/questions/12082314/… atau jawaban Ricky untuk pertanyaan ini.
bgporter
1
@ bk0 tampaknya metode Anda hanya valid untuk kamus, dan bukan string.
JD Gamboa
1021

Python 2

Apa yang Anda cari adalah 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

Dalam Python 3, urllibpaket telah dipecah menjadi komponen yang lebih kecil. Anda akan menggunakan urllib.parse.quote_plus(perhatikan parsemodul anak)

import urllib.parse
urllib.parse.quote_plus(...)
Ricky
sumber
4
Terima kasih! Namun dalam kasus saya saya harus meletakkan:import urllib.parse ... urllib.parse.quote_plus(query)
ivkremer
3
sangat bagus, tetapi mengapa tidak digunakan untuk Unicode? jika string url adalah Unicode, saya harus menyandikannya ke UTF-8. Apakah ada cara lain untuk melakukannya?
Karl Doenitz
7
Ini berfungsi dengan baik, tetapi saya tidak dapat mengakses beberapa layanan online (REST) ​​sampai saya menambahkan parameter ini safe = '; /
?:
Saya mencobanya dengan Python 3 tetapi tidak dapat: stackoverflow.com/questions/40557606/…
amfibi
1
python3 -c "import urllib.parse, sys; print(urllib.parse.quote_plus(sys.argv[1])) "string to encode"untuk satu liner di baris perintah
Amos Joshua
52

Coba permintaan alih-alih urllib dan Anda tidak perlu repot dengan urlencode!

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

EDIT:

Jika Anda membutuhkan pasangan nama-nilai yang dipesan atau beberapa nilai untuk sebuah nama, maka tetapkan params seperti ini:

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

alih-alih menggunakan kamus.

Barney
sumber
5
Ini tidak membahas masalah pemesanan pasangan nilai nama, juga ini memerlukan izin untuk menginstal perpustakaan eksternal yang mungkin tidak dapat dilakukan untuk proyek.
dreftymac
Saya memposting kode minimal yang dapat digunakan untuk OP. OP tidak meminta pasangan yang dipesan tetapi itu juga bisa dilakukan, lihat pembaruan saya.
Barney
@dreftymac: ini alamat pemesanan (walaupun itu bukan bagian dari pertanyaan), silakan baca jawaban saya yang diperbarui.
Barney
36

Konteks

  • Python (versi 2.7.2)

Masalah

  • Anda ingin membuat string kueri yang urlencode.
  • Anda memiliki kamus atau objek yang berisi pasangan nama-nilai.
  • Anda ingin dapat mengontrol urutan output dari pasangan nama-nilai.

Larutan

  • urllib.urlencode
  • urllib.quote_plus

Perangkap

Contoh

Berikut ini adalah solusi lengkap, termasuk bagaimana menghadapi beberapa jebakan.

### ********************
## 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
sumber
23

Coba ini:

urllib.pathname2url(stringToURLEncode)

urlencodetidak akan berfungsi karena hanya berfungsi pada kamus. quote_plustidak menghasilkan output yang benar.

Charlie
sumber
Itu sangat membantu! Dalam kasus saya, saya hanya memiliki sebagian dari string yang saya ingin URL-encode, misalnya saya ingin mengubah my stringke my%20string. Solusi Anda bekerja seperti pesona untuk itu!
TanguyP
Berfungsi bagi saya untuk mendapatkan %20alih-alih +. Terima kasih
Jossef Harush
21

Perhatikan bahwa urllib.urlencode tidak selalu berhasil. Masalahnya adalah bahwa beberapa layanan peduli dengan urutan argumen, yang hilang ketika Anda membuat kamus. Untuk kasus seperti itu, urllib.quote_plus lebih baik, seperti yang disarankan Ricky.

pengguna411279
sumber
2
Ini berfungsi dengan baik dan mempertahankan pesanan jika Anda melewati daftar tupel:>>> import urllib >>> urllib.urlencode([('name', 'brandon'), ('uid', 1000)]) 'name=brandon&uid=1000'
Brandon Rhodes
8

Dalam Python 3, ini berhasil dengan saya

import urllib

urllib.parse.quote(query)
Mazen Aly
sumber
6

untuk referensi di masa mendatang (mis: untuk python3)

>>> import urllib.request as req
>>> query = 'eventName=theEvent&eventDescription=testDesc'
>>> req.pathname2url(query)
>>> 'eventName%3DtheEvent%26eventDescription%3DtestDesc'
nickanor
sumber
1
biasanya Anda hanya ingin url mengkodekan nilai, apa yang telah Anda lakukan di sini akan membuat kueri GET yang tidak valid
Codewithcheese
Output untuk 'c:/2 < 3'pada Windows adalah '///C://2%20%3C%203'. Saya ingin sesuatu yang hanya keluaran 'c:/2%20%3C%203'.
binki
3

Untuk digunakan dalam skrip / program yang perlu mendukung python 2 dan 3, modul enam menyediakan fungsi quote dan 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
sumber
2

Jika urllib.parse.urlencode () memberi Anda kesalahan, maka Coba modul urllib3.

The sintaks adalah sebagai berikut:

import urllib3
urllib3.request.urlencode({"user" : "john" }) 
Natesh bhat
sumber
1

Hal lain yang mungkin belum disebutkan adalah bahwa urllib.urlencode()akan menyandikan nilai kosong dalam kamus sebagai Noneganti parameter yang tidak ada. Saya tidak tahu apakah ini biasanya diinginkan atau tidak, tetapi tidak cocok dengan kasus penggunaan saya, maka saya harus menggunakannya quote_plus.

Yusuf
sumber
0

Untuk Python 3 urllib3 berfungsi dengan baik, Anda dapat menggunakan sebagai berikut sesuai dokumen resmi :

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
sumber