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

Posted

技术标签:

【中文标题】如何修复 websocket-client Python 模块中的 CERTIFICATE_VERIFY_FAILED 错误?【英文标题】:How to fix CERTIFICATE_VERIFY_FAILED error in websocket-client Python module? 【发布时间】:2018-03-05 13:29:39 【问题描述】:

代码:

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

我试图从 Binance 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 How to create Python secure websocket client request? 上发现了这个问题,并按照此代码的步骤操作

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

但随后发生了 NameError:

NameError: name 'ssl' is not defined

我试图添加一个导致 SyntaxError 的异常(这很荒谬但仍然......)。

其他范围

我尝试了使用 wss:// 但在第一个代码本身中运行良好的不同 websocket API。

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

条件:

我在 websockets.org 上尝试了 Echo 测试,并且 wss url 功能齐全。

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

感谢您阅读我的问题。

websocket-client 的 GitHub 网址:https://github.com/websocket-client/websocket-client

【问题讨论】:

当我尝试时,您的示例代码引发了一个不同的异常,TypeError: __init__() takes exactly 4 arguments (1 given) 用于 WebSocket 初始化程序。您使用的是什么版本的 websocket?你的例子真的适合你吗? 我遇到了一个非常糟糕的错误pastebin.com/RiHn025Z 你会在最后一行代码中找到 SSL 错误。 如果您在问题中包含该回溯,*** 上的任何人都不会介意。事实上,它是首选。但是您没有回答有关您使用的是什么版本的 websocket 的问题。 我会记住这一点。错误很长,所以我只包括最后一部分。我正在使用 websocket-client 0.47.0 【参考方案1】:

在 Mac OS X 上,通过单击 Applications 文件夹的 Python 目录中的“Install Certificates.command”文件解决了问题。

要运行该命令,请打开一个新的 Finder 窗口。单击“应用程序”。然后点击安装Python的目录。例如,“Python 3.7”。最后,启动“安装 Certificates.command 文件。

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

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

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

【讨论】:

确实这个问题似乎只与 websocket-client 库有关,结合 OSX 和 Binance Websocket。该解决方案确实为我解决了所有问题,并且避免了禁用 ssl 证书验证。它实际上将 certifi 包更新到其最新版本: pip install --upgrade certifi【参考方案2】:

似乎 websocket-client 发布了自己的根证书捆绑包(坏主意),并且发布的捆绑包不包含签署 stream2.binance.com 证书的 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 使用操作系统提供的 default 根证书包。但是,我看不到使用 websocket-client 执行此操作的简单方法。您可能希望将 Autobahn 视为更具特色和可靠的替代方案。

【讨论】:

我在 GitHub 上的这个库中发现了很多问题。我想,我需要通过高速公路看到它。我希望它是一个灵活的模块,可以与不同的 Websocket 一起使用。感谢您的努力。 @superhead 你在 celery 任务中运行高速公路吗?任何想法如何实现这一目标【参考方案3】:

sslopt="cert_reqs": ssl.CERT_NONE 的方式是正确的。当你得到一个 NameError: NameError: name 'ssl' is not defined 你需要 import ssl 它应该可以工作。解决了我与 SSL 相关的问题。

【讨论】:

【参考方案4】:

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

不确定较新版本的 websocket-client 发生了什么(从 0.51.0 开始的 sn-p),但较旧的 _http.py(已链接)有一个 if 子句,而新的仅依赖于环境变量。不幸的是,它没有在我阅读的任何文档中列出。排查了很久才找到这个位,然后我找到了这个页面。似乎 websocket-client 可以更好地处理这个问题。

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

【讨论】:

以上是关于如何修复 websocket-client Python 模块中的 CERTIFICATE_VERIFY_FAILED 错误?的主要内容,如果未能解决你的问题,请参考以下文章

pip install, 如何修复 ImportError

使用Python websocket-client多线程

使用 Python websocket-client 多线程

检查python脚本是不是正在运行

python web-socket客户端这个日志来自哪里?

websocket通信 实现java模拟一个client与webclient通信