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 上右上角具有绿色安全标识

查找资料后

  1. 如果网站是<有效证书>,那么 verify=False 或者 True 都可以访问。
  2. 可以自己传入参数设置CA_BUNDLE文件或者具有CA 证书的目录。
  3. 可以指定一个本地证书作为客户端证书(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.

不理解的问题

  1. CA_BUNDLE文件或CA 证书是否就是第三方机构颁发的具有数字签名的证书?在什么情况下需要自己指定,如何获取此文件呢?
  2. ssl client cert file客户端证书文件的作用是什么?如何获取?爬虫过程中需要自己指定吗?
  3. 问题中提到的访问 SSLError 异常可能是什么导致的?

对问题 3 的猜测

  • 使用代理 IP 一部分不支持 https。
  • 目标站点服务器对请求作了限制。

接下来的动作

  • 了解 https 证书 /验证的基础知识
  • 读 requests 或 urllib3 关于 ssl 验证这块的源码
  • 在 github/request/issue 寻找答案

如果您能看到这里,真的非常感谢
如果各位老哥有了解或遇到过类似的问题可以帮忙一起讨论,灰常谢谢!


Python爬虫中requests库请求HTTPS站点时,verify参数和ssl client cert文件分别指什么?如何获取这些文件?

7 回复

爬虫建议直接不验证证书
客户端证书不需要。


在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 后面应该就可以正常访问了。

回到顶部