ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【Python】DAY02学习日记,记一次惨绝人寰的debug

2020-11-05 08:02:04  阅读:349  来源: 互联网

标签:证书 Python DAY02 验证 SSL HTTPS verify debug requests


解决在启用Fiddler的环境里,爬虫报requests.exceptions.SSLError的问题

错误原因

image.png

源自:https://www.zhihu.com/question/42104344/answer/158407685

感谢知乎老哥通俗易懂又深刻的解释!

解决办法:

1.在requests.get()里设置参数verify = FALSE,跳过验证环节

response = requests.get(url,verify = False)

但是这样会报一个很烦人的InsecureRequestWarning,所以需要加上下面的代码:

import urllib3
urllib3.disable_warnings()

这样就完美解决了。

2.理论上可以导出Fiddler的根证书,使用OpenSSL转换成.pem格式,然后设置verify的值为证书的路径,验证的时候就会去验证Fiddler的根证书。但我不知道为什么,我这样做了,却没有成功,报的错误是:

OSError: Could not find a suitable TLS CA certificate bundle, 
invalid path: Bili_Index/new.pem

参考资料来源:
官方文档ssl-warnings
http与https代理中的差异及细节
HTTP:07---连接管理之(Connection首部
TLS详解
详解 HTTPS、TLS、SSL、HTTP区别和关系
python使用requests挂fiddler代理时提示SSLError,HTTPSConnectionPool
知乎-少年晓琦OliverCh的回答)

感谢 !

——前来debug的游客请止步——

因为下面全是毫无意义的废话。

可算是明白了一杯茶一包烟一个Bug调一天的感觉了。
但是作为一个第二天学习Python的小萌新,我不禁思考,第二天就遇到了如此严峻、如此惨绝人寰的问题,是不是应该早点苦海无涯回头是岸?

先来看看报错信息

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证书验证失败:无法获取本地颁布的证书
在处理上述异常期间,又来了异常:
urllib3中的最大重试错误:重试访问url超过最大连接数:由SSLError引起(SSL证书错误[SSL证书验证失败])
requests中的SSLError:HTTPS连接池:重试访问url超过最大连接数:由SSLError引起(SSL证书错误[SSL证书验证失败])
(狗屁不通......)

尝试分析以上的错误信息:每个报错都写着,SSL证书验证失败,但是为什么开着Fiddler代理就会出现这个问题呢?
因为requests的根证书和Fiddler的根证书冲突了,并且requests的证书验证是默认开启的。

尝试解决办法1:关闭SSL证书验证。

response = requests.get(url,verify=False)

验证失败那就不验证了嘛。
尝试结果:我去,不仅没有解决,还甩了一个不安全警告。

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,

不安全请求警告:正在向主机发出未经验证的HTTPS请求。强烈建议增加证书验证。
另外这里还有个配套的不安全警告处理措施,就是禁用警告

import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

感觉不太合适的样子。

既然甩了一个官方文档的连接,那就去看看嘛。
追溯到官方的文档:https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
在里面,我注意到这样的信息:

image.png

HTTP和HTTPS代理
HTTP和HTTPS代理都支持HTTP和HTTPS目标。其中唯一的差别是,是否需要先向代理创建一个TLS(传输层协议)连接。你可以通过指定正确的代理方案来指定你所需要连接的代理。

问题又来了,我虽然把Fiddler当工具在用,但我真的不懂HTTP和HTTPS代理是什么,那就了解一下。
找到了一篇好文章:https://www.cnblogs.com/selol/p/5446965.html

image.png

看到上面的图我深受启发,所以Connection首部又是什么啊。
找到了一篇好文章:https://blog.csdn.net/qq_41453285/article/details/95162180

image.png

谜底揭开了。

然后我理解了这两句话:
image.png
所以服务器和客户端达成keep-alive共识的时候,代理层懵逼了,我是谁我在哪儿你俩想干啥,得,关连接吧。

接着博主的文章往下看:

image.png

哦哦哦原来如此,盲中继没有理解Proxy-Connection这个Conection首部的其他首部字段名,并且转发了这个字段。

接着看:

image.png

image.png

image.png

我好像理解了!感谢博主!

划重点:HTTPS代理两侧连接是同步的,要断一起断。

把目光转向之前没看完的官方文档:

image.png

HTTPS 代理+ HTTPS 目标
一个TLS-in-TSL 隧道(?)将被创建。一个初始的TLS连接将被创建给代理,然后发送一个HTTP连接来创建一个通往目标的TCP连接,最后创建第二个通往目标的TLS连接。你可以自定义ssl.SSLContext用于通过ProxyManager类的proxy_ssl_context参数进行代理TLS连接。
(狗屁不通X2)

我勉强理解一下,就是先创建一个初始TLS连接给代理,然后......算了我理解不了,先去搜搜看什么是TSL连接吧。

找到了一篇写得很好的文章:https://www.jianshu.com/p/1fc7130eb2c2

TLS握手过程:

image.png

看完了,还没太理解,又找到了另一篇好文章:https://blog.csdn.net/chan70707/article/details/82932153

我好像懂得了什么:
image.png

回头看看报错信息:

ssl.SSLCertVerificationError: 
[SSL: CERTIFICATE_VERIFY_FAILED]
 certificate verify failed: unable to get local issuer certificate 

证书验证失败的原因是:没有获取到本地颁布的证书。

对啊,那我为什么不想办法告诉它怎么获取证书呢?

尝试解决办法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)

(我现在好饿......)

接下来,我把FiddlerRoot证书导出,用OpenSSL把它从.cer转换成.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")

好了,又一次失败的尝试。

不过也有惊喜哦,那就是关了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] 由于目标计算机积极拒绝,无法连接。')))

好家伙,竟然敢拒绝我。
这下连HTTPS连接都建立不了。
(算了,休息会儿,回来面向百度debug)

回来了。
积极百度了一下还是运行不了。

草,我是智障吗!
我都把Fiddler关了,还怪人家为什么连不上代理!!!
呜呜呜呜呜对不起我的错。
我这就把Fiddler打开。

哎,还是熟悉的SSLError。

 SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] 

这还能咋办呢,回头去看看官方文档吧,叹气。

image.png

对于HTTPS代理,我们还支持使用绝对URI将请求转发到HTTPS目的地,前提是use_forwarding_For_HTTPS参数设置为True。我们强烈建议您仅将此选项用于受信任的代理或公司代理,因为代理将完全可见您的请求。

这我设置的没问题哈,略过这条。

这一条是关于上面的InsecureRequestWarning:
image.png

所以官方文档还得多读,再翻翻看。

发现了关键字Certificate Verification:
image.png

上面提示HTTPS连接现在是默认验证了。
虽然可以通过设置cert_reqs = 'CERT_NONE'来拒绝证书验证,但是还是强烈建议顺其自然。
除非另外指定的urllib3将尝试加载默认系统证书商店,最值得信赖的的跨平台方法是使用certifi包,它提供Mozilla的根证书包。

既然官网都这么说了,那就整一个?
image.png

太慢了,真的太慢了,这下载速度。

继续官方文档:
一旦你拥有证书,你可以创建一个PoolManager,在发送请求的时候验证证书。

image.png

啊这......跟我好像关系不是很大嘛。
目前要解决的问题是:
certificate verify failed: unable to get local issuer certificate
可是指定证书给它,它还是报这个错误。

不活了。

草草草草草草可以了!
就是加个参数verify=FALSE!
能跑出来不过有个不安全警告!
之前没有跑出来是因为我一共写了两个get():

response = requests.get(url,verify=False)
img = requests.get(iurl,verify=False,timeout = 5).content

但是我刚刚只补了一个verify=False。

总之程序跑出来了,警告的话忽略就行了,去看看Fiddler抓到的包——

image.png

User-Agent:python-requests/2.24.0
Connection:keep-alive
长连接是没问题的。

好像还发现了什么奇怪的东西?
image.png

Host: ocsp.globalsign.com是什么啊......

image.png

验证证书的啊,明白了。

注意到下载完最后一张图片以后,Conection依然是Keep-Alive:

image.png

好像这样也行吧,程序能跑,Fiddler能抓包,不安全警告可以disable掉,就是没有证书验证的环节。

但是,全局设置不验证ssl证书——

ssl._create_default_https_context =ssl._create_unverified_context

也运行不出来,还是报相同的错误。

继续探索正常验证证书的办法。

无意间看到有老哥解释的原因:

image.png

https://www.zhihu.com/question/42104344/answer/158407685

这个解释真是清晰明了!!!

最后提到的,将fiddler中下载的证书在requests中的参数设置,这方法我用过,不行的啊。
不如再试试?

试了,报错报错报错报错......

破案了!!我写错路径了!!

原来写的绝对路径:

verify=r"D:\py文件\Bili_Index\fdlroot.pem"

改成相对路径以后:

verify=r"Bili_Index/fdlroot.pem"

报的错误信息变化了耶!

image.png

OSError: Could not find a suitable TLS CA certificate bundle, 
invalid path: Bili_Index/fdlroot.pem

让我来看看错误是什么...invalid path....好的哦。
可是路径是我从pycharm里面右键copy path的,所以这其实是解析路径的时候出了什么问题吧。

等等......如果其实证书是无效的呢?

我重新导出一下证书,再换成.pem格式。

image.png

reset再重来。

image.png

image.png

image.png

警告多得我很恐慌,总觉得自己在按川川办公室的核*弹按钮。

image.png

重新试了一下还是报相同的错误。

应该还是证书的问题吧,搜了一下,验证12306的证书的时候,也会报这个错误。而我刚刚注意到这里:
image.png

OSError: Could not find a suitable TLS CA certificate bundle, 
invalid path: Bili_Index/new.pem

我死心了,全网没找到办法,stackoverflow上面有个问题很像但不是。

饿死了,吃饭去。

标签:证书,Python,DAY02,验证,SSL,HTTPS,verify,debug,requests
来源: https://www.cnblogs.com/northwest332/p/13929724.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有