Как urlencode строки запроса в Python?

552

Я пытаюсь кодировать эту строку перед отправкой.

queryString = 'eventName=' + evt.fields["eventName"] + '&' + 'eventDescription=' + evt.fields["eventDescription"]; 
Джеймс
источник

Ответы:

561

Вам нужно передать ваши параметры в urlencode()виде отображения (dict) или последовательности из двух кортежей, например:

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

Python 3 или выше

Использование:

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

Обратите внимание, что это не делает кодирование URL в общепринятом смысле (посмотрите на вывод). Для этого используйте urllib.parse.quote_plus.

bgporter
источник
12
«Обратите внимание, что urllib.urlencode не всегда справляется с задачей. Проблема в том, что некоторые службы заботятся о порядке аргументов, который теряется при создании словаря. В таких случаях urllib.quote_plus лучше, как предложил Рики. "
Blairg23
16
Технически, это ошибка в сервисах, не так ли?
holdenweb
5
и как можно это сделать, если вы просто хотите обезопасить строку URL, не создавая строку аргумента полного запроса?
Майк 'Pomax' Камерманс
1
@ Mike'Pomax'Kamermans - см., Например, stackoverflow.com/questions/12082314/… или ответ Рики на этот вопрос.
bgporter
1
@ bk0 кажется, ваш метод действителен только для словарей, но не для строк.
JD Gamboa
1021

Python 2

То, что вы ищете, это 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

В Python 3 urllibпакет был разбит на более мелкие компоненты. Вы будете использовать urllib.parse.quote_plus(обратите внимание на parseдочерний модуль)

import urllib.parse
urllib.parse.quote_plus(...)
Рики
источник
4
Спасибо! В моем случае, однако, мне нужно поставить:import urllib.parse ... urllib.parse.quote_plus(query)
ivkremer
3
очень хорошо, но почему не используется Unicode? Если строка URL-адреса Unicode, я должен кодировать его в UTF-8. Есть ли другой способ сделать это?
Карл Дениц
7
Это прекрасно работает, но я не мог получить доступ к некоторым онлайн-сервисам (REST), пока не добавил этот параметр safe = '; /?: @ & = + $,'
rovyko
Я пробовал это в Python 3, но не смог: stackoverflow.com/questions/40557606/…
амфибия
1
python3 -c "import urllib.parse, sys; print(urllib.parse.quote_plus(sys.argv[1])) "string to encode"для одного вкладыша в командной строке
Амос Джошуа
52

Попробуйте запросы вместо urllib, и вам не нужно беспокоиться об urlencode!

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

РЕДАКТИРОВАТЬ:

Если вам нужны упорядоченные пары имя-значение или несколько значений для имени, установите параметры следующим образом:

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

вместо использования словаря.

гулянка
источник
5
Это не решает проблему упорядочения пар «имя-значение», а также требует разрешения для установки внешних библиотек, которые могут быть недоступны для проекта.
dreftymac
Я разместил минимальный код, который будет работать для OP. ОП не запрашивал заказанные пары, однако это также выполнимо, см. Мое обновление.
Барни
@dreftymac: здесь указывается порядок адресов (хотя это не было частью вопроса), пожалуйста, прочитайте мой обновленный ответ.
Барни
36

контекст

  • Python (версия 2.7.2)

проблема

  • Вы хотите сгенерировать строку запроса в кодировке urlenco.
  • У вас есть словарь или объект, содержащий пары имя-значение.
  • Вы хотите иметь возможность управлять порядком вывода пар имя-значение.

Решение

  • urllib.urlencode
  • urllib.quote_plus

Ловушки

пример

Ниже приводится полное решение, в том числе о том, как справиться с некоторыми подводными камнями.

### ********************
## 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"    : "user@example.com",
  }

### ********************
## 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
источник
23

Попробуй это:

urllib.pathname2url(stringToURLEncode)

urlencodeне будет работать, потому что работает только со словарями. quote_plusне выдал правильный вывод.

Чарли
источник
Это действительно полезно! В моем случае у меня есть только часть строки, которую я хочу закодировать в URL, например, я хочу преобразовать my stringв my%20string. Ваше решение работает как очарование для этого!
TanguyP
Работал на меня, чтобы получить %20вместо +. Спасибо
Йосеф Харуш
21

Обратите внимание, что urllib.urlencode не всегда делает свое дело. Проблема в том, что некоторые сервисы заботятся о порядке аргументов, который теряется при создании словаря. Для таких случаев лучше использовать urllib.quote_plus, как предложил Рики.

user411279
источник
2
Он отлично работает и сохраняет порядок, если вы передаете список кортежей:>>> import urllib >>> urllib.urlencode([('name', 'brandon'), ('uid', 1000)]) 'name=brandon&uid=1000'
Брэндон Родс
8

В Python 3 это работало со мной

import urllib

urllib.parse.quote(query)
Мазен Али
источник
6

для будущих ссылок (например: для python3)

>>> import urllib.request as req
>>> query = 'eventName=theEvent&eventDescription=testDesc'
>>> req.pathname2url(query)
>>> 'eventName%3DtheEvent%26eventDescription%3DtestDesc'
nickanor
источник
1
обычно вам нужно только url кодировать значения, то, что вы сделали здесь, сделало бы недействительный запрос GET
Codewithcheese
Выход для 'c:/2 < 3'Windows есть '///C://2%20%3C%203'. Я хочу что-то, что будет просто выводить 'c:/2%20%3C%203'.
Бинки
3

Для использования в сценариях / программах, которые должны поддерживать как Python 2, так и 3, шестой модуль предоставляет функции quote и 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
источник
2

Если urllib.parse.urlencode () выдает ошибки, попробуйте модуль urllib3.

Синтаксис выглядит следующим образом :

import urllib3
urllib3.request.urlencode({"user" : "john" }) 
Натеш бхат
источник
1

Еще одна вещь, которая, возможно, уже не упоминалась, - это urllib.urlencode()то, что пустые значения в словаре будут кодироваться как строка Noneвместо того, чтобы этот параметр отсутствовал. Я не знаю, является ли это обычно желательным или нет, но не подходит для моего варианта использования, поэтому я должен использовать quote_plus.

Джозеф
источник
0

Для Python 3 urllib3 работает правильно, вы можете использовать его в соответствии с его официальной документацией :

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
источник