解決在啟用Fiddler的環(huán)境里严就,爬蟲報requests.exceptions.SSLError的問題
錯誤原因
源自:https://www.zhihu.com/question/42104344/answer/158407685
感謝知乎老哥通俗易懂又深刻的解釋!
解決辦法:
1.在requests.get()里設(shè)置參數(shù)verify = FALSE谤草,跳過驗(yàn)證環(huán)節(jié)
response = requests.get(url,verify = False)
但是這樣會報一個很煩人的InsecureRequestWarning,所以需要加上下面的代碼:
import urllib3
urllib3.disable_warnings()
這樣就完美解決了莺奸。
2.理論上可以導(dǎo)出Fiddler的根證書丑孩,使用OpenSSL轉(zhuǎn)換成.pem格式,然后設(shè)置verify的值為證書的路徑灭贷,驗(yàn)證的時候就會去驗(yàn)證Fiddler的根證書温学。但我不知道為什么,我這樣做了甚疟,卻沒有成功仗岖,報的錯誤是:
OSError: Could not find a suitable TLS CA certificate bundle,
invalid path: Bili_Index/new.pem
參考資料來源:
官方文檔ssl-warnings
http與https代理中的差異及細(xì)節(jié)
HTTP:07---連接管理之(Connection首部
TLS詳解
詳解 HTTPS、TLS览妖、SSL轧拄、HTTP區(qū)別和關(guān)系
python使用requests掛fiddler代理時提示SSLError,HTTPSConnectionPool
知乎-少年曉琦OliverCh的回答)
感謝 !
——前來debug的游客請止步——
因?yàn)橄旅嫒呛翢o意義的廢話。
可算是明白了一杯茶一包煙一個Bug調(diào)一天的感覺了黄痪。
但是作為一個第二天學(xué)習(xí)Python的小萌新紧帕,我不禁思考盔然,第二天就遇到了如此嚴(yán)峻桅打、如此慘絕人寰的問題,是不是應(yīng)該早點(diǎn)苦海無涯回頭是岸愈案?
先來看看報錯信息:
ssl.SSLCertVerificationError:[SSL:CERTIFICATE_VERIFY_FAILED]
certificate verify failed:unable to get local issuer certificate (_ssl.c:1056)
During handling of the above exception, another exception occurred:urllib3.exceptions.MaxRetryError:HTTPSConnectionPool(host='www.bilibili.com', port=443):
Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL:CERTIFICATE_VERIFY_FAIL
requests.exceptions.SSLError:HTTPSConnectionPool(host='www.bilibili.com', port=443): Max retries exceeded with url:/ (Caused by SSLError(SSLCertVerificationError
(1, '[SSL: CERTIFICATE_VERIFY_FAILED]
簡單翻譯一下:
SSL證書錯誤:SSL證書驗(yàn)證失斖ξ病:無法獲取本地頒布的證書
在處理上述異常期間,又來了異常:
urllib3中的最大重試錯誤:重試訪問url超過最大連接數(shù):由SSLError引起(SSL證書錯誤[SSL證書驗(yàn)證失敗])
requests中的SSLError:HTTPS連接池:重試訪問url超過最大連接數(shù):由SSLError引起(SSL證書錯誤[SSL證書驗(yàn)證失敗])
(狗屁不通......)
嘗試分析以上的錯誤信息:每個報錯都寫著站绪,SSL證書驗(yàn)證失敗遭铺,但是為什么開著Fiddler代理就會出現(xiàn)這個問題呢?
因?yàn)閞equests的根證書和Fiddler的根證書沖突了,并且requests的證書驗(yàn)證是默認(rèn)開啟的魂挂。
嘗試解決辦法1:關(guān)閉SSL證書驗(yàn)證甫题。
response = requests.get(url,verify=False)
驗(yàn)證失敗那就不驗(yàn)證了嘛。
嘗試結(jié)果:我去涂召,不僅沒有解決坠非,還甩了一個不安全警告。
InsecureRequestWarning:
Unverified HTTPS request is being made to host 'www.bilibili.com'.
Adding certificate verification is strongly advised.
See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecureRequestWarning,
不安全請求警告:正在向主機(jī)發(fā)出未經(jīng)驗(yàn)證的HTTPS請求果正。強(qiáng)烈建議增加證書驗(yàn)證炎码。
另外這里還有個配套的不安全警告處理措施,就是禁用警告:
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
感覺不太合適的樣子秋泳。
既然甩了一個官方文檔的連接潦闲,那就去看看嘛。
追溯到官方的文檔:https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
在里面迫皱,我注意到這樣的信息:
HTTP和HTTPS代理
HTTP和HTTPS代理都支持HTTP和HTTPS目標(biāo)歉闰。其中唯一的差別是,是否需要先向代理創(chuàng)建一個TLS(傳輸層協(xié)議)連接卓起。你可以通過指定正確的代理方案來指定你所需要連接的代理新娜。
問題又來了,我雖然把Fiddler當(dāng)工具在用既绩,但我真的不懂HTTP和HTTPS代理是什么概龄,那就了解一下。
找到了一篇好文章:https://www.cnblogs.com/selol/p/5446965.html
看到上面的圖我深受啟發(fā)饲握,所以Connection首部又是什么啊私杜。
找到了一篇好文章:https://blog.csdn.net/qq_41453285/article/details/95162180
謎底揭開了。
然后我理解了這兩句話:
所以服務(wù)器和客戶端達(dá)成keep-alive共識的時候救欧,代理層懵逼了衰粹,我是誰我在哪兒你倆想干啥,得笆怠,關(guān)連接吧铝耻。
接著博主的文章往下看:
哦哦哦原來如此,盲中繼沒有理解Proxy-Connection這個Conection首部的其他首部字段名蹬刷,并且轉(zhuǎn)發(fā)了這個字段瓢捉。
接著看:
我好像理解了!感謝博主办成!
劃重點(diǎn):HTTPS代理兩側(cè)連接是同步的泡态,要斷一起斷。
把目光轉(zhuǎn)向之前沒看完的官方文檔:
HTTPS 代理+ HTTPS 目標(biāo)
一個TLS-in-TSL 隧道(迂卢?)將被創(chuàng)建某弦。一個初始的TLS連接將被創(chuàng)建給代理桐汤,然后發(fā)送一個HTTP連接來創(chuàng)建一個通往目標(biāo)的TCP連接,最后創(chuàng)建第二個通往目標(biāo)的TLS連接靶壮。你可以自定義ssl.SSLContext用于通過ProxyManager類的proxy_ssl_context參數(shù)進(jìn)行代理TLS連接怔毛。
(狗屁不通X2)
我勉強(qiáng)理解一下,就是先創(chuàng)建一個初始TLS連接給代理腾降,然后......算了我理解不了馆截,先去搜搜看什么是TSL連接吧。
找到了一篇寫得很好的文章:http://www.reibang.com/p/1fc7130eb2c2
TLS握手過程:
看完了蜂莉,還沒太理解蜡娶,又找到了另一篇好文章:https://blog.csdn.net/chan70707/article/details/82932153
我好像懂得了什么:
回頭看看報錯信息:
ssl.SSLCertVerificationError:
[SSL: CERTIFICATE_VERIFY_FAILED]
certificate verify failed: unable to get local issuer certificate
證書驗(yàn)證失敗的原因是:沒有獲取到本地頒布的證書。
對啊映穗,那我為什么不想辦法告訴它怎么獲取證書呢窖张?
嘗試解決辦法2:指定SSL證書。
https://blog.csdn.net/qq_33958297/article/details/82291009
按照這篇文章里的步驟操作了一下蚁滋,失敗了orz宿接。
gProxies = {"http":"http://192.168.1.103:8888","https":"http://192.168.1.103:8888"}
cert = "D:\py文件\Bili_Index\\fiddlerroot.crt"
response = requests.get(url,proxies=gProxies,verify=cert)
(我現(xiàn)在好餓......)
接下來,我把FiddlerRoot證書導(dǎo)出辕录,用OpenSSL把它從.cer轉(zhuǎn)換成.pem睦霎,然后把我的代碼改成了這個樣子:
response = requests.get(url,
proxies={"http": "http://127.0.0.1:8888",
"https":"http:127.0.0.1:8888"},
verify="D:\py文件\Bili_Index\\fdlroot.pem")
好了,又一次失敗的嘗試走诞。
不過也有驚喜哦副女,那就是關(guān)了Fiddler,還附送了一個臉生的新錯誤哦:
requests.exceptions.ProxyError:
HTTPSConnectionPool(host='www.bilibili.com', port=443):
Max retries exceeded with url:
/ (Caused by ProxyError('Cannot connect to proxy.', NewConnectionError
('<urllib3.connection.HTTPSConnection object at 0x00000251156835C0>:
Failed to establish a new connection:
[WinError 10061] 由于目標(biāo)計算機(jī)積極拒絕蚣旱,無法連接碑幅。')))
好家伙,竟然敢拒絕我塞绿。
這下連HTTPS連接都建立不了沟涨。
(算了,休息會兒异吻,回來面向百度debug)
回來了裹赴。
積極百度了一下還是運(yùn)行不了。
草诀浪,我是智障嗎棋返!
我都把Fiddler關(guān)了,還怪人家為什么連不上代理K裢住0米颉!
嗚嗚嗚嗚嗚對不起我的錯春宣。
我這就把Fiddler打開酵颁。
哎,還是熟悉的SSLError月帝。
SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED]
這還能咋辦呢躏惋,回頭去看看官方文檔吧,嘆氣嚷辅。
對于HTTPS代理簿姨,我們還支持使用絕對URI將請求轉(zhuǎn)發(fā)到HTTPS目的地,前提是use_forwarding_For_HTTPS參數(shù)設(shè)置為True簸搞。我們強(qiáng)烈建議您僅將此選項(xiàng)用于受信任的代理或公司代理扁位,因?yàn)榇韺⑼耆梢娔恼埱蟆?/p>
這我設(shè)置的沒問題哈,略過這條趁俊。
這一條是關(guān)于上面的InsecureRequestWarning:
所以官方文檔還得多讀域仇,再翻翻看。
發(fā)現(xiàn)了關(guān)鍵字Certificate Verification:
上面提示HTTPS連接現(xiàn)在是默認(rèn)驗(yàn)證了寺擂。
雖然可以通過設(shè)置cert_reqs = 'CERT_NONE'來拒絕證書驗(yàn)證暇务,但是還是強(qiáng)烈建議順其自然。
除非另外指定的urllib3將嘗試加載默認(rèn)系統(tǒng)證書商店怔软,最值得信賴的的跨平臺方法是使用certifi包垦细,它提供Mozilla的根證書包。
既然官網(wǎng)都這么說了挡逼,那就整一個括改?
太慢了,真的太慢了家坎,這下載速度叹谁。
繼續(xù)官方文檔:
一旦你擁有證書,你可以創(chuàng)建一個PoolManager乘盖,在發(fā)送請求的時候驗(yàn)證證書焰檩。
啊這......跟我好像關(guān)系不是很大嘛。
目前要解決的問題是:
certificate verify failed: unable to get local issuer certificate
可是指定證書給它订框,它還是報這個錯誤析苫。
不活了。
草草草草草草可以了穿扳!
就是加個參數(shù)verify=FALSE衩侥!
能跑出來不過有個不安全警告!
之前沒有跑出來是因?yàn)槲乙还矊懥藘蓚€get():
response = requests.get(url,verify=False)
img = requests.get(iurl,verify=False,timeout = 5).content
但是我剛剛只補(bǔ)了一個verify=False矛物。
總之程序跑出來了茫死,警告的話忽略就行了,去看看Fiddler抓到的包——
User-Agent:python-requests/2.24.0
Connection:keep-alive
長連接是沒問題的履羞。
好像還發(fā)現(xiàn)了什么奇怪的東西峦萎?
Host: ocsp.globalsign.com是什么啊......
驗(yàn)證證書的啊屡久,明白了。
注意到下載完最后一張圖片以后爱榔,Conection依然是Keep-Alive:
好像這樣也行吧被环,程序能跑,F(xiàn)iddler能抓包详幽,不安全警告可以disable掉筛欢,就是沒有證書驗(yàn)證的環(huán)節(jié)。
但是唇聘,全局設(shè)置不驗(yàn)證ssl證書——
ssl._create_default_https_context =ssl._create_unverified_context
也運(yùn)行不出來版姑,還是報相同的錯誤。
繼續(xù)探索正常驗(yàn)證證書的辦法迟郎。
無意間看到有老哥解釋的原因:
https://www.zhihu.com/question/42104344/answer/158407685
這個解釋真是清晰明了0铡!谎亩!
最后提到的炒嘲,將fiddler中下載的證書在requests中的參數(shù)設(shè)置,這方法我用過匈庭,不行的啊夫凸。
不如再試試?
試了阱持,報錯報錯報錯報錯......
破案了X舶琛!我寫錯路徑了V匝省鸽扁!
原來寫的絕對路徑:
verify=r"D:\py文件\Bili_Index\fdlroot.pem"
改成相對路徑以后:
verify=r"Bili_Index/fdlroot.pem"
報的錯誤信息變化了耶!
OSError: Could not find a suitable TLS CA certificate bundle,
invalid path: Bili_Index/fdlroot.pem
讓我來看看錯誤是什么...invalid path....好的哦镶骗。
可是路徑是我從pycharm里面右鍵copy path的懦尝,所以這其實(shí)是解析路徑的時候出了什么問題吧牵素。
等等......如果其實(shí)證書是無效的呢路媚?
我重新導(dǎo)出一下證書箍鼓,再換成.pem格式。
reset再重來相寇。
警告多得我很恐慌慰于,總覺得自己在按川川辦公室的核*彈按鈕。
重新試了一下還是報相同的錯誤唤衫。
應(yīng)該還是證書的問題吧婆赠,搜了一下,驗(yàn)證12306的證書的時候佳励,也會報這個錯誤休里。而我剛剛注意到這里:
OSError: Could not find a suitable TLS CA certificate bundle,
invalid path: Bili_Index/new.pem
我死心了蛆挫,全網(wǎng)沒找到辦法,stackoverflow上面有個問題很像但不是份帐。
餓死了璃吧,吃飯去楣导。