若只想让一个 urllib opener 直接连接,请向 ProxyHandler 传入空映射:

from urllib.request import ProxyHandler, build_opener

direct = build_opener(ProxyHandler({}))

with direct.open("https://example.com/", timeout=10) as response:
    print(response.status)

空字典不提供任何代理路由。若省略映射,处理器则会从环境和平台设置中发现代理。这两种构造方式表达的是不同策略。

示例使用 Python 标准库,并保留正常的 HTTPS 验证。with 代码块会关闭响应,即使因异常离开代码块也一样。

在同一应用中同时使用直连和代理请求

两个 opener 可以分别承载两种策略,无须在两次调用间修改环境变量:

from urllib.request import ProxyHandler, build_opener

direct = build_opener(ProxyHandler({}))
proxied = build_opener(ProxyHandler({
    "http": "http://127.0.0.1:8080",
    "https": "http://127.0.0.1:8080",
}))

with proxied.open("https://example.com/", timeout=10) as response:
    print(response.status)

将回环地址替换为你的 HTTP 代理,或从 HTTP 代理列表中选择候选来比较代理请求。如果服务允许,它可以通过 CONNECT承载 HTTPS 目标连接。请确保监听端的协议和认证支持与处理器匹配。

保留默认 opener

通过负责对应路由的对象调用 direct.open 或 proxied.open。install_opener 会修改 urllib 便捷调用所使用的进程级默认 opener,因此库调用它可能影响无关代码。上面隔离使用的 opener 不需要它。

timeout 参数是单项操作设置,不是每次传输从开始到结束的完整时间上限。只读取任务所需的数据;若任务有严格的总耗时预算,请使用更高层的截止时间。

这些 opener 对象不会修改其他库的客户端、已有进程或浏览器的代理设置。

相关文章