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

82 投票
7 回答
87941 浏览
提问于 2025-04-18 05:32

我正在尝试使用 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)

有没有什么方法可以以原始形式传递参数,而不进行百分比编码呢?

谢谢!

7 个回答

5

以上提到的所有解决方案在requests版本2.26之后似乎都不再有效。GitHub上的建议解决方案似乎是使用一种叫做PreparedRequest的变通方法。

以下方法对我有效。确保你使用的URL是可以解析的,不要用'这不是一个域名.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

11

这个解决方案的设计就是直接传递网址。

15

上面的答案对我没用。

我想发送一个包含管道符号(|)的请求参数,但用Python的requests库时,它会把管道符号也进行百分比编码。所以我改用了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'
15

如果将来有人遇到这个问题,你可以通过创建一个请求会话的子类,重写发送方法,来修改原始网址,从而修正百分比编码等问题。欢迎对下面的内容进行补充和修正。

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.")
95

这不是最好的解决办法,但你可以直接使用 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 来进行测试。

撰写回答