Python爬虫中requests库请求HTTPS站点时,verify参数和ssl client cert文件分别指什么?如何获取这些文件?
使用requests做爬虫(目标站点为 https 站点)时遇到以下问题:
先贴上伪代码
response = requests.get(url=self.url, headers=self.headers, params=self.params,
proxies={"https": self.get_proxy()}, timeout=5, verify=False)
- 多线程访问
- 做了 https 代理,每一段时间(约 10s )请求使用的 ip 都会不一样:
现在的情况是
- 使用上面的代码可以访问,但是部分请求会抛出如下异常。
- 这部分异常请求约 30%,十分影响采集效率。
<class 'requests.exceptions.SSLError'> HTTPSConnectionPool(host='xxxx.com', port=443):
Max retries exceeded with url: xxxx.com
(Caused by SSLError(SSLError("bad handshake: Error
([('SSL routines', 'ssl3_get_record', 'wrong version number')],)",),))
网站在 chrome 上右上角具有绿色安全标识
查找资料后
- 如果网站是<有效证书>,那么 verify=False 或者 True 都可以访问。
- 可以自己传入参数设置
CA_BUNDLE文件或者具有CA 证书的目录。 - 可以指定一个本地证书作为客户端证书(
client side certificate),可以是如下形式。
# 设置`CA_BUNDLE`文件
requests.get('https://github.com', verify='/path/to/certfile')
# 指定一个本地证书作为客户端证书
requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))
requests.get('https://kennethreitz.org', cert='/path/client.cert')
参考链接: http://www.python-requests.org/en/latest/user/advanced/#ssl-cert-verification
requests 源码对 verify 和 cert 参数的注释
:param verify: (optional) Either a boolean,in which case it controls whether we verify
the server's TLS certificate, or a string,in which case it must be a path to a CA bundle
to use. Defaults to ``True``.
:param cert: (optional) if String, path to ssl client cert file (.pem).
If Tuple, (‘cert’, ‘key’) pair.
不理解的问题
CA_BUNDLE文件或CA 证书是否就是第三方机构颁发的具有数字签名的证书?在什么情况下需要自己指定,如何获取此文件呢?ssl client cert file客户端证书文件的作用是什么?如何获取?爬虫过程中需要自己指定吗?- 问题中提到的访问 SSLError 异常可能是什么导致的?
对问题 3 的猜测
- 使用代理 IP 一部分不支持 https。
- 目标站点服务器对请求作了限制。
接下来的动作
- 了解 https 证书 /验证的基础知识
- 读 requests 或 urllib3 关于 ssl 验证这块的源码
- 在 github/request/issue 寻找答案
如果您能看到这里,真的非常感谢
如果各位老哥有了解或遇到过类似的问题可以帮忙一起讨论,灰常谢谢!
Python爬虫中requests库请求HTTPS站点时,verify参数和ssl client cert文件分别指什么?如何获取这些文件?
爬虫建议直接不验证证书
客户端证书不需要。
在Python爬虫里用requests库请求HTTPS站点时,verify参数和SSL客户端证书(client cert)是两码事,但都和安全校验有关。
1. verify参数
这个参数是用来验证服务器的SSL证书是否可信。默认是True,意味着requests会检查:
- 证书是否由受信任的机构(CA)签发
- 证书中的域名和你访问的域名是否匹配
- 证书是否在有效期内
如果服务器用的是自签名证书(比如公司内网测试环境),证书不在受信任的CA列表中,直接请求会报SSLError。这时候你有两个选择:
- 设置
verify=False:直接跳过验证(不推荐,有安全风险) - 设置
verify='/path/to/cert.pem':把你得到的服务器证书(或CA证书)文件路径传给它,requests会用这个文件来验证
如何获取服务器证书文件?
对于自签名的情况,你需要从服务器管理员那里拿到.pem或.crt格式的证书文件。如果是公开网站,一般不需要手动指定。
2. SSL客户端证书文件 这是另一回事,是用来向服务器证明客户端身份的。有些严格的API或银行接口会要求客户端提供证书。通常需要两个文件:
- 证书文件(比如
client.crt) - 私钥文件(比如
client.key)
在requests里这么用:
import requests
resp = requests.get(
'https://example.com/api',
cert=('/path/to/client.crt', '/path/to/client.key')
)
如何获取客户端证书?
这必须由服务器方(或你们公司的安全部门)签发给你,自己生成是没用的。通常会给你一个.p12或.pfx文件,你需要用OpenSSL命令转换成.crt和.key:
# 提取证书
openssl pkcs12 -in client.p12 -out client.crt -nokeys
# 提取私钥
openssl pkcs12 -in client.p12 -out client.key -nocerts -nodes
简单总结
verify管服务器靠不靠谱,client cert管你是谁。
不是 SSL 版本问题吗?还 SSL3 ?
嗯,这个参数验证过,加不加上目前都没有影响。至于 ssl3 我还不太懂…
根据配置与调试 SSL 的经验:
1. CA bundle file 是一个文件,包含 PEM(base64)编码的、被信任的所有根证书(CA Root)。Python 可能不使用操作系统的证书系统,就像 Mozilla 的 NSS。
2. ssl client cert file 是用于 SSL 双向认证的客户端证书,通常还有一个对应的私钥。一般的网站不使用双向认证,故在大多数情况下无需配置。
这个 ssl3 很可能是 OpenSSL 的代码 /API 中的命名空间。
不表示正在使用 SSLv3
谢谢老哥!有些懂了。
python 访问 https 验证数字证书依赖的是 python 第三方库certifi(安装 requests 默认安装),certifi会在
Linux 非虚拟环境路径<br>/usr/local/lib/python2.7/dist-packages/certifi/cacert.pem<br>
或者虚拟环境路径<br>/root/.virtualenvs/virName/lib/python3.5/site-packages/certifi/cacert.pem<br>
创建一个.pem 文件
也就是说我去访问一个 https 网站 certifi 的 cacert.pem 文件会提供我需要验证的证书,所以能够正常访问。
同理如果我去访问一个第三方没有授权证书的 https 网站(例如 12306 自己做的证书),我就把 12306 的 CA Root 添加到 cacert.pem 后面应该就可以正常访问了。

