Как запретить запросам python процентное кодирование моих URL-адресов?

Я пытаюсь ПОЛУЧИТЬ URL-адрес следующего формата, используя request.get() в python:

http://api.example.com/export/?format=json&key=site%3adummy+type%3aexample+group%3awheel

#!/usr/local/bin/python

import requests

print(requests.__versiom__)
url = 'http://api.example.com/export/'
payload = {'format': 'json', 'key': 'site:dummy+type:example+group:wheel'}
r = requests.get(url, params=payload)
print(r.url)

Однако URL-адрес кодируется в процентах, и я не получаю ожидаемого ответа.

2.2.1
http://api.example.com/export/?key=site%3Adummy%2Btype%3Aexample%2Bgroup%3Awheel&format=json

Это работает, если я передаю URL напрямую:

url = http://api.example.com/export/?format=json&key=site:dummy+type:example+group:wheel
r = requests.get(url)

Есть ли способ передать параметры в их исходном виде - без процентного кодирования?

Спасибо!


person Satyen Rai    schedule 06.05.2014    source источник
comment
Это стандарт. Что с этим не так?   -  person alecxe    schedule 06.05.2014
comment
@alecxe: Сайт, который я запрашиваю, похоже, не работает с URL-адресами, закодированными в процентах, и я получаю неожиданный ответ.   -  person Satyen Rai    schedule 06.05.2014
comment
У меня возникла эта проблема с API Карт Google и запятой в location=43.585278,39.720278, и я не нашел решения.   -  person furas    schedule 06.05.2014


Ответы (5)


Это не очень хорошее решение, но вы можете использовать напрямую string:

r = requests.get(url, params='format=json&key=site:dummy+type:example+group:wheel')

Кстати:

Код, который преобразует payload в эту строку

payload = {
    'format': 'json', 
    'key': 'site:dummy+type:example+group:wheel'
}

payload_str = "&".join("%s=%s" % (k,v) for k,v in payload.items())
# 'format=json&key=site:dummy+type:example+group:wheel'

r = requests.get(url, params=payload_str)

ИЗМЕНЕНИЕ (2020 г.):

Вы также можете использовать urllib.parse.urlencode(...) с параметром safe=':+' для создания строки без преобразования символов :+ .

Насколько я знаю, requests также использует для этого urllib.parse.urlencode(...), но без safe=.

import requests
import urllib.parse

payload = {
    'format': 'json', 
    'key': 'site:dummy+type:example+group:wheel'
}

payload_str = urllib.parse.urlencode(payload, safe=':+')
# 'format=json&key=site:dummy+type:example+group:wheel'

url = 'https://httpbin.org/get'

r = requests.get(url, params=payload_str)

print(r.text)

Я использовал страницу https://httpbin.org/get для проверки.

person furas    schedule 06.05.2014
comment
Спасибо, это то, что я сейчас делаю, чтобы заставить его работать. Я ищу решение, похожее на (устаревшее) описанное здесь. Спасибо, в любом случае! - person Satyen Rai; 06.05.2014
comment
Я искал лучшее решение (похожее на устаревшее) в исходном коде запросов, но не нашел. - person furas; 06.05.2014
comment
работал на меня. на вид не супер, но со своей задачей справляется. я подумал, что может быть какое-то более простое решение, настроив кодировку в объекте requests. - person ryantuck; 19.02.2015
comment
Я использую %XX, где XX — шестнадцатеричные цифры. Отправка строк для параметров работает до тех пор, пока я не попытаюсь отправить что-то большее, чем 2F, после чего я получаю сообщение об ошибке «Недопустимый управляющий символ». - person retsigam; 16.08.2018
comment
urllib.parse.urlencode не игнорирует фигурные скобки при синтаксическом анализе. self.response = requests.get(SteamQuery.queries[self.query_type], params=urllib.parse.urlencode(self.query_params,safe=":{}[]")) input_json=%7Bappids_filter:[892970]%7D - person user1023102; 26.02.2021

Решение, как задумано, заключается в прямой передаче URL-адреса.

person Kenneth Reitz    schedule 06.05.2014
comment
Идея использования словаря полезной нагрузки, чтобы сделать фактический код несколько чище - как предложено здесь. - person Satyen Rai; 06.05.2014
comment
Я нашел этот старый комментарий @Darkstar довольно забавным, поскольку ответ, на который он отвечает, принадлежит автору requests. - person Dustin Wyatt; 14.07.2016
comment
@DustinWyatt Вау! Я не знаю, как я пропустил это! - person Satyen Rai; 14.07.2016
comment
Это самое простое и проверенное рабочее решение. Откажитесь от словаря полезной нагрузки и вставьте все эти параметры прямо в URL-адрес. - person Rakaim; 22.10.2020

На случай, если кто-то еще столкнется с этим в будущем, вы можете подклассифицировать запросы. Сеанс, переопределить метод отправки и изменить необработанный URL-адрес, чтобы исправить кодировку процентов и тому подобное. Исправления нижеприведенного приветствуются.

import requests, urllib

class NoQuotedCommasSession(requests.Session):
    def send(self, *a, **kw):
        # a[0] is prepared request
        a[0].url = a[0].url.replace(urllib.parse.quote(","), ",")
        return requests.Session.send(self, *a, **kw)

s = NoQuotedCommasSession()
s.get("http://somesite.com/an,url,with,commas,that,won't,be,encoded.")
person Brandon McGinty-Carroll    schedule 17.11.2016
comment
Я знаю, что этого не было в вопросе ОП, но это не работает для части URL-адреса пути (на момент написания этого комментария). - person Tim Ludwinski; 12.04.2021

Ответы выше не работали для меня.

Я пытался выполнить запрос на получение, где параметр содержал канал, но запросы python также процентно кодировали канал. Поэтому вместо этого я использовал urlopen:

# python3
from urllib.request import urlopen

base_url = 'http://www.example.com/search?'
query = 'date_range=2017-01-01|2017-03-01'
url = base_url + query

response = urlopen(url)
data = response.read()
# response data valid

print(response.url)
# output: 'http://www.example.com/search?date_range=2017-01-01|2017-03-01'
person kujosHeist    schedule 17.03.2017

Пожалуйста, взгляните на первый вариант в этой ссылке на github. Вы можете игнорировать urlibчасть, что означает prep.url = url вместо prep.url = url + qry

person Sandeep Kanabar    schedule 10.05.2018