使用web3.py訪問infura節點的時候(https://mainnet.infura.io/v3/XXXXXXXXXXXXXXX)的時候出現以下錯誤:
requests.exceptions.ProxyError: HTTPSConnectionPool(host='mainnet.infura.io', port=443): Max retries exceeded with url: /v3/xxx(Caused by ProxyError('Unable to connect to proxy', ReadTimeoutError("HTTPSConnectionPool(host='mainnet.infura.io', port=443): Read timed out. (read timeout=10)")))
先說結論,這個是因為使用了系統全域性代理導致的,全域性代理設定成http_proxy=http://localhost:8001,https_proxy=https://localhost:8001,
問題就出在https_proxy,它的值不應該是=https://localhost:8001,而應該跟http_proxy的值一致,那麼就不會報錯了!
只需要在系統環節變數中設定環境變數:https_proxy=https://localhost:8001,https_proxy=http://localhost:8001,這樣web3.py會使用這個設定去訪問代理
這個原因我找了兩三天時間,說一下是怎麼找到的:
1、我先在以上報錯文字中發現proxy的字樣,所以我懷疑是網路問題,但是不用全域性代理又無法連線infura節點,所以我第一步想到可能是程式無法透過全域性代理訪問外網,我要先設定訪問路徑載入程式訪問,然後我開始設定PyCharm的代理,設定如下:
2、設定完畢後,我想在web3.py中找到設定代理的程式碼,然後修改一下,但是怎麼找都找不到,只能說我看原始碼的水平有限,所以就放棄了這個方法。
3、然後我開始嘗試用最原始的requests包看看會不會報錯,我執行以下程式碼:
import requests
s = requests.session()
s.keep_alive = False
url = 'https://mainnet.infura.io/v3/xxxxxx'
requests.adapters.DEFAULT_RETRIES = 5
s = requests.session()
s.keep_alive = False;
response = requests.get(url=url, verify=False)
print(response) # 請求狀態
print(response.content) # 返回結果
這次執行的結果出現這個錯誤:
requests.exceptions.ProxyError: HTTPSConnectionPool(host='mainnet.infura.io', port=443): Max retries exceeded with url: /v3/xxxxxx (Caused by ProxyError('Unable to connect to proxy. Your proxy appears to only use HTTP and not HTTPS, try changing your proxy URL to be HTTP. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#https-proxy-error-http-proxy', SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1091)'))))
這次有一個明顯的提示: Your proxy appears to only use HTTP and not HTTPS, try changing your proxy URL to be HTTP
而且還給了一個幫助網址:https://urllib3.readthedocs.io/en/latest/advanced-usage.html#https-proxy-error-http-proxy,
大概意思就是說我的代理軟體不支援https代理,只支援http代理,但是我的訪問地址是https開頭的,所以web3.py就會去連https的埠,但是連過去又發現代理軟體不支援https,所以就報錯了!
我將https://mainnet.infura.io/v3/xxxxxx,改成http://mainnet.infura.io/v3/xxxxxx,這樣雖然問題就解決了,但是infura節點不支援這樣訪問,返回404,所以必須是https開頭的,按上面那個網址中介紹的思路,只能改系統配置了,將https的對映值改成http://localhost:8001,不帶s的
也就是讓web3.py在解析https開頭的網址時,也使用代理軟體的http埠去訪問,
使用以下程式碼檢視當前代理的環境變數配置,要先獲得代理軟體的埠,
import urllib.request
print(urllib.request.getproxies())
輸出結果是:
{'https': 'https://localhost:8001', 'http': 'http://localhost:8001'}
注意,每個代理軟體使用的埠都是不同的,我的軟體用的是8001
但https://urllib3.readthedocs.io/en/latest/advanced-usage.html#https-proxy-error-http-proxy全文沒有提到怎麼改變代理對映值,我又找了新的資料,我看到urllib.request.getproxies()中,有獲得環境變數的程式碼片段,getproxies_environment()中將字尾是”_proxy”的環境變數的值都讀出來了,所以我就在系統環境變數中加入了兩個值,如下:
修改以後,記得要重啟Pycharm,這樣才能讀到新值!
自此所有問題解決!