Python: 如何只URL编码特定的URL参数?

Python: How to only URL Encode a specific URL Parameter?

我有一些大 URL 包含很多 URL 参数。

对于我的具体情况,当“q=”之后的内容以斜杠(“/” )

示例URL:

https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=/"TEST"/"TEST"

我如何才能 URL 编码“q”参数中 URL 的最后一部分?

这个例子的输出应该是:

https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=%2F%22TEST%22%2F%22TEST%22%20

我已经用 urllib.parse 尝试了一些不同的东西,但它并不像我想要的那样工作。

感谢您的帮助!

拆分 &q=/ 部分的字符串,只对最后一个字符串进行编码

from urllib import parse

url = 'https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=/"TEST"/"TEST"'
encoded = parse.quote_plus(url.split("&q=/")[1])
encoded_url = f"{url.split('&q=/')[0]}&q=/{encoded}"
print(encoded_url)

输出

https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=%2F%22TEST%22%2F%22TEST%22

请注意,这与请求的输出之间存在差异,但您在末尾有一个 url 编码的 space (%20)


编辑

评论显示对编码的不同需求,因此代码需要稍微更改一下。下面的代码只对&q=之后的部分进行了编码。基本上,首先拆分 url 和参数,然后遍历参数以找到 q= 参数,并对那部分进行编码。做一些 f-string 并加入魔法,你会得到一个 url,其中 q 参数已编码。请注意,如果需要编码的部分中存在 &,这可能会出现问题。

url = 'https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=/"TEST"/"TEST"&utm_source=test1&cpc=123&gclid=abc123'
# the first parameter is always delimited by a ?
baseurl, parameters = url.split("?")
newparameters = []
for parameter in parameters.split("&"):
    # check if the parameter is the part that needs to be encoded
    if parameter.startswith("q="):
        # encode the parameter
        newparameters.append(f"q={parse.quote_plus(parameter[2:])}")
    else:
        # otherwise add the parameter unencoded
        newparameters.append(parameter)
# string magic to create the encoded url
encoded_url = f"{baseurl}?{'&'.join(newparameters)}"
print(encoded_url)

输出

https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=%2F%22TEST%22%2F%22TEST%22&utm_source=test1&cpc=123&gclid=abc123

编辑 2

尝试解决要编码的字符串中有 & 个字符的边缘情况,因为这会弄乱 string.split("&")
我尝试使用 urllib.parse.parse_qs() 但这与 & 字符有相同的问题。 Docs供参考。

这个问题很好地说明了边缘情况如何弄乱简单的逻辑并使其变得过于复杂。

RFC3986 也没有对查询字符串的名称指定任何限制,否则可以用来进一步缩小可能的错误范围。

更新代码

from urllib import parse


url = 'https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=/"TEST"/&"TE&eeST"&utm_source=test1&cpc=123&gclid=abc123'
# the first parameter is always delimited by a ?
baseurl, parameters = url.split("?")

# addition to handle & in the querystring.
# it reduces errors, but it can still mess up if there's a = in the part to be encoded.
split_parameters = []
for index, parameter in enumerate(parameters.split("&")):
    if "=" not in parameter:
        # add this part to the previous entry in split_parameters
        split_parameters[-1] += f"&{parameter}"
    else:
        split_parameters.append(parameter)


newparameters = []
for parameter in split_parameters:
    # check if the parameter is the part that needs to be encoded
    if parameter.startswith("q="):
        # encode the parameter
        newparameters.append(f"q={parse.quote_plus(parameter[2:])}")
    else:
        # otherwise add the parameter unencoded
        newparameters.append(parameter)
# string magic to create the encoded url
encoded_url = f"{baseurl}?{'&'.join(newparameters)}"
print(encoded_url)

输出

https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=%2F%22TEST%22%2F%26%22TE%26eeST%22&utm_source=test1&cpc=123&gclid=abc123

@EdoAkse 有一个很好的答案,应该得到答案。

但我的纯粹主义者会做同样的事情略有不同,因为

(1) 我不喜欢对同一个数据做同一个函数两次(为了效率),并且

(2) 我喜欢使用 join 函数反转拆分的逻辑对称性。

我的代码看起来更像这样:

from urllib import parse

url = 'https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=/"TEST"/"TEST"'
splitter = "&q=/"   
unencoded,encoded = url.split(splitter)
encoded_url = splitter.join(unencoded,parse.quote_plus(encoded))
print(encoded_url)  

编辑:我忍不住发布了我根据评论编辑过的答案。你可以看到独立开发的虚拟相同代码。我想这一定是正确的方法。

from urllib import parse
url = 'https://www.exmple.com/test?test1=abc&test2=abc&test3=abc&q=/"TEST"/"TEST"'
base_url,arglist = url.split("?",1)
args = arglist.split("&")
new_args = []
for arg in args:
    if arg.lower().startswith("q="):
        new_args.append(arg[:2]+parse.quote_plus(arg[2:]))
    else:
        new_args.append(arg)
encoded_url = "?".join([base_url,"&".join(new_args)])
print(encoded_url)