使用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 寻找答案
如果您能看到这里,真的非常感谢
如果各位老哥有了解或遇到过类似的问题可以帮忙一起讨论,灰常谢谢!