如何仅对URL协议后的部分执行quote编码?有无现成工具及处理已编码URL?
仅对URL协议后的部分进行Quote编码的正确方法
一、用标准库urllib.parse的URL解析工具(推荐)
直接使用urlsplit和urlunsplit,这是专门针对URL标准结构设计的工具,比简单字符串分割靠谱得多,能完美解决你提到的各类边界问题:
from urllib.parse import quote, urlsplit, urlunsplit start_url = "https://commons.wikimedia.org/wiki/File:Jan Hackaert, Small Town (Town Gate at Gorkum?), NGA 53482.jpg" # 按URL标准结构拆分为:(scheme, netloc, path, query, fragment) url_components = urlsplit(start_url) # 仅对路径、查询参数、锚点部分编码,协议和域名保持原样 encoded_path = quote(url_components.path) encoded_query = quote(url_components.query) encoded_fragment = quote(url_components.fragment) # 重新组合成完整URL quoted_url = urlunsplit( ( url_components.scheme, url_components.netloc, encoded_path, encoded_query, encoded_fragment ) ) print(quoted_url)
这个方法严格遵循RFC标准拆分URL,不会被路径中的://干扰,也能处理无协议的URL(比如//example.com/path或相对路径/path/here)——如果原URL没有协议,url_components.scheme会是空字符串,组合后仍能保持正确格式。
二、处理已编码过的URL
如果URL已经被编码过,直接二次编码会导致重复转义(比如%20变成%2520),需要先解码再重新编码:
from urllib.parse import quote, unquote, urlsplit, urlunsplit encoded_url = "https://www.example.com/path%20with%20spaces" # 先解码还原原始URL decoded_url = unquote(encoded_url) # 再用上述方法重新编码 url_components = urlsplit(decoded_url) encoded_path = quote(url_components.path) quoted_url = urlunsplit( (url_components.scheme, url_components.netloc, encoded_path, url_components.query, url_components.fragment) ) print(quoted_url)
unquote会把已转义的字符还原为原始字符,之后再编码就能保证结果无重复转义、格式正确。
三、原方法的问题说明
你之前用split("://",1)的写法存在以下硬伤:
- 无法处理无协议的URL,会因
url_parts只有一个元素导致访问url_parts[1]报错 - 若路径中包含
://(比如文件名内的字符串),会错误分割URL,导致编码范围出错 - 未区分URL的不同组成部分,可能误编码域名(虽然域名一般无特殊字符,但理论上存在带特殊字符的国际域名,这类域名本身应使用Punycode编码)
四、开箱即用的封装方案
urllib.parse没有直接一键完成该操作的函数,但可以用urlsplit+urlunsplit组合封装成工具函数,实现便捷调用:
from urllib.parse import quote, unquote, urlsplit, urlunsplit def quote_url_after_scheme(url, decode_first=False): if decode_first: url = unquote(url) components = urlsplit(url) return urlunsplit( ( components.scheme, components.netloc, quote(components.path), quote(components.query), quote(components.fragment) ) ) # 用法示例 # 编码未处理过的URL print(quote_url_after_scheme("https://commons.wikimedia.org/wiki/File:Jan Hackaert, Small Town (Town Gate at Gorkum?), NGA 53482.jpg")) # 对已编码URL先解码再编码 print(quote_url_after_scheme("https://www.example.com/path%20with%20spaces", decode_first=True))
内容的提问来源于stack exchange,提问作者Laurent Claessens
相关产品推荐
相关产品推荐

