简体   繁体   English

在 python 查询参数中使用 %20 而不是 + 作为空格

[英]Use %20 instead of + for space in python query parameters

I have written the following python script, using python requests ( http://requests.readthedocs.org/en/latest/ ):我使用 python 请求( http://requests.readthedocs.org/en/latest/ )编写了以下 python 脚本:

import requests

payload = {'key1': 'value  1', 'key2': 'value 2'}
headers = {'Content-Type': 'application/json;charset=UTF-8'}
r = requests.get("http://example.com/service", params=payload, headers=headers, 
             auth=("admin", "password"))

If I look at the access log of the server, the incoming request is: /service?key1=value++1&key2=value+2如果我查看服务器的访问日志,传入的请求是:/service?key1=value++1&key2=value+2

However, the server expects ... value%20%201& ...但是,服务器期望 ... value%20%201& ...

I have read that using a + as a placeholder for a space is part of content type application/x-www-form-urlencoded, but clearly I have requested application/json.我已经读到使用 + 作为空格的占位符是内容类型 application/x-www-form-urlencoded 的一部分,但显然我已经请求了 application/json。

Anybody know how to use %20 as a space in query parameters of pythons requests?有人知道如何在pythons请求的查询参数中使用%20作为空格吗?

To follow up on @WeaselFox's answer, they introduced a patch that accepts a quote_via keyword argument to urllib.parse.urlencode .为了跟进@ WeaselFox的答案,他们介绍了接受一个补丁quote_via关键字参数urllib.parse.urlencode Now you could do this:现在你可以这样做:

import requests
import urllib

payload = {'key1': 'value  1', 'key2': 'value 2'}
headers = {'Content-Type': 'application/json;charset=UTF-8'}
params = urllib.parse.urlencode(payload, quote_via=urllib.parse.quote)
r = requests.get("http://example.com/service", params=params, headers=headers,
    auth=("admin", "password"))

I only find urllib.parse.quote , which can replace space to %20 .我只找到urllib.parse.quote ,它可以将空格替换为%20

But quote could not convert a dict.但是quote无法转换字典。

so, We must use quote to transform dict in advance.所以,我们必须提前使用quote来转换dict。


#for python3
from urllib.parse import quote

payload = {'key1': 'value  1', 'key2': 'value 2'}

newpayload = {}
for (k, v) in payload.items():
    newpayload[quote(k)] = quote(v)
print(newpayload)
#print result: {'key1': 'value%20%201', 'key2': 'value%202'}
# Now, you can use it in requests

this seems to be a known bug/issue in python :这似乎是 python 中的一个已知错误/问题:

http://bugs.python.org/issue13866 http://bugs.python.org/issue13866

I think you will have to go around this issue using urllib and urllib2 and avoid requests.我认为您将不得不使用urlliburllib2解决这个问题并避免请求。 look at the bug reports for some tips on how to do that.查看错误报告以获取有关如何执行此操作的一些提示。

We can use urllib2.Request to call url我们可以使用 urllib2.Request 来调用 url

import urllib2

send_params = {'key1': 'value  1', 'key2': 'value 2'}
new_send_params = []
for (k, v) in send_params.items():
    new_send_params.append(k + "=" + urllib2.quote(v))

url = 'http://example.com/service?'+ '&'.join(new_send_params)
req = urllib2.Request(url)
response = urllib2.urlopen(req)
print "Request URL: " + url
#Request URL: http://example.com/service?key1=value%20&key2=value%202
print response.read()
#Python Master Request handler 2016-07-04 16:05:19.928132 . Your request path is  /service?key1=value%20&key2=value%202

PYTHON 2.7蟒蛇 2.7

  • Override the urllib.quote_pluse with urllib.quote覆盖与urllib.quoteurllib.quote_pluse

  • The urlencoder uses urllib.quote_pluse to encode the data. urlencoder 使用 urllib.quote_pluse 对数据进行编码。


code代码

import requests
import urllib
urllib.quote_plus=urllib.quote # A fix for urlencoder to give %20 
payload = {'key1': 'value  1', 'key2': 'value 2'}
headers = {'Content-Type': 'application/json;charset=UTF-8'}
param = urllib.urlencode(payload) #encodes the data
r = requests.get("http://example.com/service", params=param, headers=headers, 
             auth=("admin", "password"))

output输出

the output for param = urllib.urlencode(payload)
'key2=value%202&key1=value%20%201' 
from urllib.parse import urlencode

def to_query_string(params):
    return urlencode(params, doseq=True).replace('+', '%20')

You could pass a string to params instead of a dictionary, and manually handle the spaces. 您可以将字符串传递给 params而不是字典,并手动处理空格。

Maybe something along the lines of 也许类似的东西

 
 
  
  def to_query_string(p, s=''): for k in p: v = p[k] if isinstance(v, str): s += f'{k}={v}&'.replace(' ', '%20') elif isinstance(v, int): s += f'{k}={v}&' elif isinstance(v, list): for i in v: s += f'{k}={i}&' return s[:-1] # remove last '&'
 
 
which can be used as 可以用作
min = 10 max = 30 params = {'query': f'score between {min} and {max}', 'limit': 1, 'information': ['name', 'location']} response = get('/api/dogs', params=to_query_string(params))

requests uses internally quote() from urllib.parse requests内部使用来自urllib.parse quote()

import requests
from requests.utils import quote

url='https://api-adresse.data.gouv.fr/search/'
requests.get(url, params='q='+quote('rue du Jura')).url

https://api-adresse.data.gouv.fr/search/?q=rue%20du%20Jura

If you give a str/byte (and not a dict), requests don't encode you params如果您提供 str/byte(而不是 dict),则requests不会对您的参数进行编码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM