如何修复websocket-client Python模块中的CERTIFICATE_VERIFY_FAILED错误?



Code:

import websocket
ws = websocket.WebSocket()
ws.connect('wss://stream2.binance.com:9443/ws/!miniTicker@arr@3000ms')
record  = ws.recv()
print(record)

我试图从币安Websocket API获取实时数据。 尝试使用此示例 URL 获取数据

wss://stream.binance.com:9443/ws/bnbbtc@depth

我收到此错误,指出SSL验证失败。

ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)

回溯 : pastebin.com/RiHn025Z

我已经尝试过的:

所以我在SO上发现了这个问题 如何创建Python安全websocket客户端请求? 并按照此代码的步骤进行操作

ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE})
ws.connect("wss://stream2.binance.com:9443/ws/!miniTicker@arr@3000ms")

但随后发生了名称错误:

NameError: name 'ssl' is not defined

我试图添加一个异常(这很荒谬,但仍然......),这导致了语法错误。

其他范围

我尝试使用使用 wss://的不同 websocket API,但在第一个代码本身中工作得很好。

wss://ws.blockchain.info/inv
{"op":"ping"}

条件:

我在 websockets.org 上尝试了回声测试,wss url 功能齐全。

任何帮助将不胜感激。 还有其他专门用于币安的模块,但我想拥有原始数据,所以我正在使用这个 api。

感谢您阅读我的问题。

websocket-client 的 GitHub URL : https://github.com/websocket-client/websocket-client

在 Mac OS X 上,通过单击位于">应用程序"文件夹的 Python 目录中的">安装 Certificates.command"文件可以解决问题。

要运行该命令,请打开一个新的 Finder 窗口。点击"应用程序"。然后单击安装 Python 的目录。例如,"Python 3.7"。最后,踢"安装证书.命令文件。

所有这些都可以通过在终端应用程序中执行以下命令来完成:

open "/Applications/Python 3.7/Install Certificates.command"

注意:您需要登录到下载并安装 Python 3.7 的帐户。

sslopt={"cert_reqs": ssl.CERT_NONE}的方式是正确的。当您收到名称错误:NameError: name 'ssl' is not defined您需要import ssl它应该有效。解决了我的SSL相关问题。

似乎websocket-client提供了自己的根证书包(坏主意),并且它提供的捆绑包不包括签署stream2.binance.com证书(oops)的CA的特定CA证书。

您可以通过将 websocket-client 指向更好的捆绑包来解决此问题。 例如,在 Ubuntu 上,我有一个很好的捆绑包 操作系统在/etc/ssl/certs/ca-certificates.pem. 因此:

WEBSOCKET_CLIENT_CA_BUNDLE=/etc/ssl/certs/ca-certificates.pem python wsexample.py

这样做,我得到了您的示例程序转储的一些数据,大概是您所追求的数据。

更好的方法是告诉 websocket-client 使用操作系统提供的默认根证书包。 但是,我没有看到使用websocket-client执行此操作的简单方法。 您可能想看看高速公路是一个功能更强大、更可靠的替代方案。

http://pydoc.net/websocket-client/0.46.0/websocket._http/

不确定较新版本的 websocket-client(0.51.0 中的片段)发生了什么,但较旧的 _http.py(链接)有一个 if 子句,而新版本仅依赖于环境变量。不幸的是,它没有列在我阅读的任何文档中。花了很长时间进行故障排除以找到此位,然后我找到了此页面。似乎websocket客户端可以更好地处理这个问题。

def _ssl_socket(sock, user_sslopt, hostname):
sslopt = dict(cert_reqs=ssl.CERT_REQUIRED)
sslopt.update(user_sslopt)
certPath = os.environ.get('WEBSOCKET_CLIENT_CA_BUNDLE')
if certPath and os.path.isfile(certPath) 
and user_sslopt.get('ca_certs', None) is None 
and user_sslopt.get('ca_cert', None) is None:
sslopt['ca_certs'] = certPath
elif certPath and os.path.isdir(certPath) 
and user_sslopt.get('ca_cert_path', None) is None:
sslopt['ca_cert_path'] = certPath

检查SSL从哪里选择证书。

import ssl
ssl.get_default_verify_paths()
>> DefaultVerifyPaths(cafile='/Library/Frameworks/Python.framework/Versions/3.8/etc/openssl/cert.pem', capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/Library/Frameworks/Python.framework/V)

import _ssl
_ssl.get_default_verify_paths()
>>('SSL_CERT_FILE', '/Library/Frameworks/Python.framework/Versions/3.8/etc/openssl/cert.pem', 'SSL_CERT_DIR', '/Library/Frameworks/Python.framework/Versions/3.8/etc/openssl/certs')

检查那里是否存在证书文件,如果没有,则在那里下载并保存证书。您可以从证书库下载证书。

import certifi
certifi.where()
>> /venv/lib/python3.8/site-packages/certifi/cacert.pem

您可以将文件复制并保存在默认位置。

其他解决方案,未经测试:可以将环境变量SSL_CERT_FILE设置为证书路径

最新更新