在 Python URL 中进行特殊字符编码 | AI生成和翻译

Home 2026.01

Question: 有时我们需要在 URL 中使用像 http://username:password@someproxy 这样的 endpoint,对吧?如果使用 password 包含 # 或 . 等字符,Python 可能会报 parse failure 错误。

Answer:

是的,在构建包含身份验证凭据(username:password@host)的 URL 时,用户名或密码中的特殊字符必须经过 percent-encoded(URL-encoded),以避免解析问题。

为什么会发生这种情况

Python 的 urllib.parse.urlparse(或 requests 等库中的类似解析器)会将 URL 拆分为多个组件。分隔符如 :@/?# 具有特殊含义:

如果密码包含 #,解析器可能会将 # 之后的所有内容视为 fragment,从而导致错误的 netloc(网络位置)以及解析错误或失败(例如,因无效的 port 或 host 导致 ValueError)。

这是 Python urllib 中的已知行为(参见相关 bug,例如除非经过编码,否则会将 #? 视为分隔符)。

正确的解决方案

使用 urllib.parse.quote(或者在某些情况下使用 quote_plus,但此处 quote 更安全,因为它不会将空格替换为 +)对用户名和/或密码进行 percent-encode。

推荐方法:通过编码手动构建 URL

from urllib.parse import quote

username = "myuser"
password = "pass#word.with.dots"  # 包含 # 和 .

encoded_username = quote(username, safe='')
encoded_password = quote(password, safe='')

proxy_url = f"http://{encoded_username}:{encoded_password}@proxyhost:port/"

# 示例输出: http://myuser:pass%23word.with.dots@proxyhost:port/

requests 库中使用 Proxies

如果使用 proxies:

import requests
from urllib.parse import quote

password = "pass#word.with.dots"
encoded_password = quote(password, safe='')

proxies = {
    "http": f"http://username:{encoded_password}@proxyhost:port/",
    "https": f"http://username:{encoded_password}@proxyhost:port/",
}

response = requests.get("https://example.com", proxies=proxies)

许多报告确认,将 # 编码为 %23,将 @ 编码为 %40 等,可以解决 requests proxies 中的解析错误。

替代方案:避免在 URL 中嵌入凭据

出于安全和简洁的考虑:

编码确保了在 host 部分之前,整个凭据字符串被正确处理。

References:


Back

x-ai/grok-4.1-fast

Donate