Mac下py2app打包应用无法找到cacert.pem,求解决办法
解决py2app打包后requests找不到cacert.pem的问题
我之前也踩过py2app打包的类似坑,尤其是Anaconda环境下,经常会因为资源路径或zip打包的逻辑导致依赖库找不到文件。结合你的情况,给你几个可行的解决思路:
1. 手动指定证书路径(最可靠方案)
requests默认通过certifi.where()获取证书路径,但打包后这个路径可能指向了app包内的zip压缩文件——而py2app的zip结构里的文件无法直接被文件系统访问。我们可以手动把证书作为独立资源打包,然后在代码里明确指定路径:
- 第一步:找到你的Anaconda环境中
cacert.pem的位置(运行python -c "import certifi; print(certifi.where())"就能得到),把它复制到你的项目根目录。 - 第二步:修改
setup.py,把证书加入py2app的资源列表:from setuptools import setup APP = ['monitor.py'] # 替换成你的主脚本文件名 OPTIONS = { 'py2app': { 'resources': ['cacert.pem'], # 把证书加入资源打包列表 'includes': ['requests', 'certifi'] # 确保依赖库被完整打包 } } setup( app=APP, options=OPTIONS, setup_requires=['py2app'] ) - 第三步:在你的代码里,获取证书的实际路径并告诉requests:
import os import requests # 获取py2app设置的资源目录路径(打包后生效,本地运行也兼容) resource_path = os.environ.get('RESOURCEPATH', os.path.dirname(os.path.abspath(__file__))) cacert_path = os.path.join(resource_path, 'cacert.pem') # 全局设置requests使用这个证书,后续请求无需重复指定 requests.Session().verify = cacert_path # 也可以每次请求单独指定:requests.get(url, verify=cacert_path)
2. 禁用py2app的zip打包
py2app默认会把依赖库打包成一个zip文件,这是路径问题的常见根源。你可以直接禁用zip打包,让所有文件以实际文件形式存在:
在setup.py里设置zipfile=None:
OPTIONS = { 'py2app': { 'zipfile': None, # 禁用zip打包,所有库文件以真实文件形式存放 'includes': ['requests', 'certifi'] } }
然后重新打包:python setup.py py2app。这样certifi就能正常找到它的证书文件了,缺点是app体积会稍微大一点,但路径问题能直接解决。
3. 覆盖certifi的路径检测逻辑
如果上面的方法都不行,你可以直接替换certifi的where()方法,强制它返回我们打包的证书路径:
import certifi import os def custom_certifi_where(): resource_path = os.environ.get('RESOURCEPATH', os.path.dirname(os.path.abspath(__file__))) return os.path.join(resource_path, 'cacert.pem') # 替换certifi默认的路径检测方法 certifi.where = custom_certifi_where
这样requests调用certifi.where()时,就会返回我们指定的证书路径了。
排查小技巧
- 可以在代码里加一行
print(certifi.where()),打包后在终端用open -a monitor.app运行app,查看控制台输出,确认它实际查找的路径是什么,再对比app包内的文件结构(右键app选择"显示包内容",进入Contents/Resources)。 - 检查app包内的
Contents/Resources/lib/python3.5/site-packages/certifi目录,看看cacert.pem是否真的存在。
内容的提问来源于stack exchange,提问作者Chuck Carlson
相关产品推荐
相关产品推荐

