【问题标题】:python requests and cx_freezepython请求和cx_freeze
【发布时间】:2014-04-29 02:55:27
【问题描述】:

我正在尝试冻结依赖于请求的 python 应用程序,但出现以下错误:

Traceback (most recent call last):
  File "c:\Python33\lib\site-packages\requests\packages\urllib3\util.py", line 630, in ssl_wrap_socket
    context.load_verify_locations(ca_certs)
FileNotFoundError: [Errno 2] No such file or directory

看起来很难找到带有可执行文件的 ssl 证书。我发现this 似乎是同样的问题,但我无法弄清楚他们是如何让它工作的。主要问题似乎是请求捆绑的证书没有复制到压缩库中。所以看来我将不得不强制 cx_freeze 捆绑证书,然后从我的脚本中指向它。

从这个简单的脚本开始一切正常:

import requests
r = requests.get("https://yourapihere.com")
print(r.json())

然后,如果我添加证书文件,我会收到错误消息:

import requests
r = requests.get("https://yourapihere.com", cert=requests.certs.where())
print(r.json())

-

Traceback (most recent call last):
  File "c:\Python33\lib\site-packages\requests\packages\urllib3\connectionpool.py", line 480, in urlopen
    body=body, headers=headers)
  File "c:\Python33\lib\site-packages\requests\packages\urllib3\connectionpool.py", line 285, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "c:\Python33\lib\http\client.py", line 1065, in request
    self._send_request(method, url, body, headers)
  File "c:\Python33\lib\http\client.py", line 1103, in _send_request
    self.endheaders(body)
  File "c:\Python33\lib\http\client.py", line 1061, in endheaders
    self._send_output(message_body)
  File "c:\Python33\lib\http\client.py", line 906, in _send_output
    self.send(msg)
  File "c:\Python33\lib\http\client.py", line 844, in send
    self.connect()
  File "c:\Python33\lib\site-packages\requests\packages\urllib3\connection.py", line 164, in connect
    ssl_version=resolved_ssl_version)
  File "c:\Python33\lib\site-packages\requests\packages\urllib3\util.py", line 637, in ssl_wrap_socket
    context.load_cert_chain(certfile, keyfile)
ssl.SSLError: [SSL] PEM lib (_ssl.c:2155)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "c:\Python33\lib\site-packages\requests\adapters.py", line 330, in send
    timeout=timeout
  File "c:\Python33\lib\site-packages\requests\packages\urllib3\connectionpool.py", line 504, in urlopen
    raise SSLError(e)
requests.packages.urllib3.exceptions.SSLError: [SSL] PEM lib (_ssl.c:2155)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "example.py", line 10, in <module>
    r = requests.get("https://yourapihere.com", cert=requests.certs.where())
  File "c:\Python33\lib\site-packages\requests\api.py", line 55, in get
    return request('get', url, **kwargs)
  File "c:\Python33\lib\site-packages\requests\api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "c:\Python33\lib\site-packages\requests\sessions.py", line 383, in request
    resp = self.send(prep, **send_kwargs)
  File "c:\Python33\lib\site-packages\requests\sessions.py", line 486, in send
    r = adapter.send(request, **kwargs)
  File "c:\Python33\lib\site-packages\requests\adapters.py", line 385, in send
    raise SSLError(e)
requests.exceptions.SSLError: [SSL] PEM lib (_ssl.c:2155)

我想我正在使用它correctly,但无法真正弄清楚它为什么不起作用。我想在修复此问题后,我可以继续并将证书添加到 cx_freeze 捆绑包中,例如:

example.py:

import os
import requests

cert = os.path.join(os.path.dirname(requests.__file__),'cacert.pem')
r = requests.get("https://yourapihere.com", cert=cert)
print(r.json())

setup.py:

from cx_Freeze import setup, Executable

import requests.certs
build_exe_options = {"zip_includes":[(requests.certs.where(),'requests/cacert.pem')]}

executables = [
    Executable('example.py')
]

setup(
      executables=executables
      )

如果有人能给我小费,将不胜感激。

【问题讨论】:

  • 在您的冻结代码中,requests.__file__ 不会指向真实文件,因为模块位于 zip 文件中。请参阅常见问题解答中的using data files
  • 我仔细检查了一下,requests.__file__ 指向 zip 文件。所以我想这很好。
  • 不,因为它不能只打开.../library.zip/requests/cacert.pem。该路径需要指向一个可以打开和读取的文件。
  • 第一个错误不是使用冻结,只是运行正常。
  • 我感觉路径应该作为verify 参数传递 - cert 似乎有所不同。

标签: python python-requests cx-freeze


【解决方案1】:

我从另一个对我有用的帖子中找到了这条评论: https://stackoverflow.com/a/25239701/3935084

总结如下:

你也可以使用环境变量“REQUESTS_CA_BUNDLE”(如http://docs.python-requests.org/en/latest/user/advanced/#ssl-cert-verification所说)

这比纠正所有请求要简单得多:

os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(os.getcwd(), "cacert.pem")

【讨论】:

  • 根据os.getcwd() 执行此操作仅在您从包含该文件的目录中运行程序时才有效。如果您创建快捷方式并从其他地方运行它,它将找不到该文件。常见问题解答中有 an entry 关于如何查找与您的 exe 相关的数据文件。
【解决方案2】:

实现此功能的步骤:

  • 明确告诉请求证书在哪里
  • 告诉 cx_freeze 在“构建”时也获取证书文件
  • 拥有在冻结时使用正确证书文件的代码

test.py:

import os
import sys

import requests

# sets the path to the certificate file
if getattr(sys, 'frozen', False):
    # if frozen, get embeded file
    cacert = os.path.join(os.path.dirname(sys.executable), 'cacert.pem')
else:
    # else just get the default file
    cacert = requests.certs.where()

# remember to use the verify to set the certificate to be used
# I guess it could also work with REQUESTS_CA_BUNDLE, but I have not tried
r = requests.get('https://www.google.com', verify=cacert)

print(r)

setup.py:

from cx_Freeze import setup, Executable
import requests
import sys

executable = Executable( script = "test.py" )

# Add certificate to the build
options = {
    "build_exe": {
        'include_files' : [(requests.certs.where(), 'cacert.pem')]
    }
}

setup(
    version = "0",
    requires = ["requests"],
    options = options,
    executables = [executable]
)

要构建它,只需:

$ python setup.py build

如果成功,您应该会看到:

$ test
<Response [200]>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-22
    相关资源
    最近更新 更多