直接在 Proxy URL 嵌入帳密 https://user:pass@proxy:port 並傳給 `ProxyHandler`,**Python 2.7 的 `urllib2` 不支援此語法**,導致 407 Proxy Authentication Required。
import urllib2
def build_proxy_opener(proxy_info):
# proxy_info = {'user': 'xxx', 'password': 'xxx', 'server': 'proxy.example.com:8080'}
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, proxy_info['server'], proxy_info['user'], proxy_info['password'])
proxy_handler = urllib2.ProxyHandler({'http': proxy_info['server']})
auth_handler = urllib2.ProxyBasicAuthHandler(password_mgr)
opener = urllib2.build_opener(proxy_handler, auth_handler)
return opener
proxy_info = {'user': 'myuser', 'password': 'mypass', 'server': 'proxy.corp.com:8080'}
opener = build_proxy_opener(proxy_info)
urllib2.install_opener(opener)
response = urllib2.urlopen('https://httpbin.org/ip')
print(response.read())
HTTPPasswordMgrWithDefaultRealm 管理認證憑證,`None` 表示適用於所有 Realm。add_password 的第 2 參數為 **代理伺服器 URI** (不含 scheme),而非目標網站 URI。ProxyBasicAuthHandler 專門處理 407 回應,自動插入 `Proxy-Authorization` 標頭。build_opener 依序傳入 `ProxyHandler` (建立隧道) 與 `ProxyBasicAuthHandler` (掛載認證)。import urllib.request
password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, 'proxy.corp.com:8080', 'myuser', 'mypass')
proxy_handler = urllib.request.ProxyHandler({'http': 'proxy.corp.com:8080'})
auth_handler = urllib.request.ProxyBasicAuthHandler(password_mgr)
opener = urllib.request.build_opener(proxy_handler, auth_handler)
urllib.request.install_opener(opener)
with urllib.request.urlopen('https://httpbin.org/ip') as f:
print(f.read().decode())
import requests
proxies = {'http': 'https://user:pass@proxy:8080', 'https': 'https://user:pass@proxy:8080'}
requests.get('https://api.example.com', proxies=proxies) # requests 完美支援 URL 嵌入帳密
結論:urllib2 必須分離 ProxyHandler 與 ProxyBasicAuthHandler;現代專案強烈建議直接使用 requests。