如何防止 python 请求对我的 URL 进行百分比编码?

Posted

技术标签:

【中文标题】如何防止 python 请求对我的 URL 进行百分比编码?【英文标题】:How to prevent python requests from percent encoding my URLs? 【发布时间】:2014-06-23 04:30:33 【问题描述】:

我正在尝试在 python 中使用 requests.get() 获取以下格式的 URL:

http://api.example.com/export/?format=json&key=site:dummy+type:example+group:wheel

#!/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)

有没有办法以原始形式传递参数 - 没有百分比编码?

谢谢!

【问题讨论】:

这是一个standard。它有什么问题? @alecxe:我正在查询的网站似乎无法使用百分比编码的 URL,并且我得到了意外的响应。 我在location=43.585278,39.720278 中使用 Google Maps API 和逗号遇到了这个问题,但我没有找到解决方案。 【参考方案1】:

这不是很好的解决方案,但你可以直接使用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来测试它。

【讨论】:

谢谢,这就是我目前正在做的事情。我正在寻找一种类似于here 描述的(过时的)解决方案。还是谢谢! 我在 requests 源代码中寻找更好的解决方案(类似于过时的解决方案)但我没有找到。 为我工作。看起来不是很好,但可以完成工作。我认为通过调整requests 对象中的编码可能会有一些更简单的解决方案。 我使用“%XX”,其中 XX 是十六进制数字。发送参数字符串一直有效,直到我尝试发送大于 2F 的内容,此时我收到“无效控制字符”错误 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【参考方案2】:

按照设计,解决方案是直接传递 URL。

【讨论】:

使用有效载荷字典来保持实际代码更清晰的想法 - 正如建议的here。 我发现@Darkstar 的这条旧评论有点有趣,因为他回复的答案是requests 的作者。 @DustinWyatt 哇!我不知道我是怎么错过的! 这是最直接且经过验证的工作解决方案。丢弃有效负载字典并将所有这些参数直接添加到 url 中。 不,这不起作用,最新版本的requests 将编码字符,即使您直接传递 URL。【参考方案3】:

万一其他人将来遇到这种情况,您可以继承 requests.Session,覆盖 send 方法,并更改原始 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.")

【讨论】:

我知道这不在 OP 的问题中,但这不适用于 URL 的路径部分(在发表此评论时)。 在现代版本的请求中,您实际上还必须修补urllib3;它执行自己的编码。 requests.urllib3.util.url.PATH_CHARS.add(',')。这开始进入“比它可能的价值更hacky”的领域,但如果你真的需要它......这里就是【参考方案4】:

上面的答案对我不起作用。

我试图在参数包含管道的情况下执行获取请求,但 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'

【讨论】:

【参考方案5】:

请查看github link 中的第一个选项。您可以忽略urlibpart,这意味着prep.url = url 而不是prep.url = url + qry

【讨论】:

【参考方案6】:

从请求版本 2.26 开始,上述所有解决方案似乎都不再适用。来自 GitHub 存储库的建议解决方案似乎正在使用 PreparedRequest 的变通方法。

以下内容对我有用。确保 URL 是可解析的,因此不要使用“this-is-not-a-domain.com”。

import requests

base_url = 'https://www.example.com/search'
query = '?format=json&key=site:dummy+type:example+group:wheel'

s = requests.Session()
req = requests.Request('GET', base_url)
p = req.prepare()
p.url += query
resp = s.send(p)
print(resp.request.url)

来源:https://github.com/psf/requests/issues/5964#issuecomment-949013046

【讨论】:

以上是关于如何防止 python 请求对我的 URL 进行百分比编码?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 System.Net.Http HttpClient 对我的请求 URL 进行编码?

如何根据域名阻止对我的 api-gateway url 的任何请求?

只允许 CloudFront 从源服务器读取?

使用多线程代码防止 DOS 攻击

python反射

如何在 Python 中对我的 Dataframe 的每一列进行 ADF 测试?