python requests 与 cx_freeze
我正在尝试将一个依赖于requests库的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证书时遇到了问题。我找到了一篇文章,似乎也是同样的问题,但我搞不清楚他们是怎么解决的。主要问题似乎是requests库打包的证书没有被复制到压缩的库中。所以我可能需要强制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)
我想我在正确使用它,但真的搞不清楚为什么不行。我想在解决这个问题后,我可以继续将证书添加到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
)
如果有人能给我一点建议,我将非常感激。
2 个回答
0
我在另一个讨论串找到了一条评论,对我有帮助:
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")
0
让这个工作起来的步骤:
- 明确告诉请求库证书在哪里
- 告诉 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]>