[Python]使用cx_Freeze打包FastApi项目的方法以及遇到的问题

前言

最近公司项目需要用到FastApi做一个打印web接口服务,然后将这个服务打包成Windows可执行程序,在使用pyinstaller打包出现问题之后,了解到Python官方推荐的是使用cx_Freeze打包。于是开始了cx_Freeze折腾

安装

使用命令安装:

pip install cx_Freeze

验证是否安装成功,打开控制台(cmd)输入:

cxfreeze -h

# 如果有类似提示则表示安装成功:Usage: cxfreeze [options] [SCRIPT]

打包exe

简单的使用

在控制台中进入到需要打包的文件夹,执行命令:

cxfreeze run.py --target-dir=build
  • run.py 表示打包的文件名称,一般为程序的入口文件
  • --target-dir=build 表示打包后的文件存放路径
    执行完成之后可以在同路径下的build/xxx/文件夹中找到刚刚打包的run.exe
    如果存在需要引入的某些三方库,用这种方法可能找不到,所以不推荐这种方法

使用setup.py进行打包

  1. 在需要打包的路径下新建一个setup.py(名字随意,你喜欢就好),输入以下内容
import sys
from cx_Freeze import setup, Executable

include_files = ['.\\printing_server\\templates\\log_websocket_client.html']

build_exe_options = {'packages': ['uvicorn','ipaddress','jinja2.ext'], 
                     'excludes': [],
                     'include_files':include_files
                     }
base = None
if sys.platform == 'win32':
  base = 'Win32GUI'

setup(  name = 'runFastApi',
        version = '0.1',
        description = '打印服务',
        options = {'build_exe': build_exe_options},
        executables = [Executable('run.py')])
  • include_files 需要引入的静态文件、动态链接库等等内容
  • packages 需要引入的三方扩展包,虽然可以自动根据py文件引入三方库进入导入,但是避免不了有些库,它无法识别,所以需要手动显性的引入
  • setup name表示文件名称,version,exe描述,options 打包时需要引入的文件或者三方库包,executables 设置程序的入口文件
  1. 然后在终端中执行命令:
python setup.py build

等待打包结束,在同级目录下会出现build目录,需要的exe文件存在build/xxx/
打包过程还算简单,可以直接运行exe进行测试了

遇到的问题

  1. 打包完成之后,直接双击会闪退,在cmd中运行exe提示ModuleNotFoundError: No module named 'xxx' 这个时候就需要在setup.py 文件中的packages文件中加入需要的扩展包
  2. 由于是web服务打包成了exe,其中不免会包含HTML等文件,打包的时候可以在include_files中指定文件路径。指定了路径之后cx_freeze会自动将文件复制到生成的可执行文件的同级目录下,这个时候仍然可能会出现提示找不到html等文件。

解决办法一:

我的文件目录:

printing_server
  |_templates(存放的是HTML文件)
  |_xxx.py
run.py
setup.py

我在xxx.py文件中指定的html文件存放位置:template = Jinja2Templates(directory=".\\printing_server\\templates")

打包成exe之后运行时会默认在当前路径下面找printing_server\templates文件夹,这个时候就会提示没有NotFound
所以我们可以在setup.py的incloude_files直接指定路径为.\\printing_server,生成exe之后在exe同级目录下会有printing_server的文件夹名称,这个时候运行exe可以正常运行。

缺点:打包时会将printing_server中的所有内容都复制过来(包括py文件),

可能会有人有疑问,说我直接在include_files中指定文件夹到templates中不就好了吗,这个倒是解决了只导入HTML等文件,但是运行的仍然会报找不到文件的错误,因为这个时候在exe的同级目录生成的文件是templates,而我们py文件中指定的是.\\printing_server\\templates,所以还是找不到

针对该缺点的解决办法:将templates文件夹放在其他不包含py文件的目录,然后重新在py文件中指定存放路径,在setup.py的include_files中引入文件夹templates(可能项目文件夹有要求,所以根据实际的来吧)。或者将exe同级目录中的静态资源文件夹中的无关资源删除

解决办法二:

后来发现一个简单的方法,简直简单不要不要的。突然发现自己好蠢哈哈哈
由于我在xxx.py文件中指定的HTML的路径为.\\printing_server\\templates, 我们可以在生成exe文件之后,在exe文件的同级目录中新建一个文件夹printing_server,然后将templates整个文件夹复制至其中,运行exe 完美!!

这个问题的原因还是因为打包成exe之后会自动在同级目录下去寻找需要的静态文件,所以只需要将py文件中指定的静态资源文件按照指定的目录存放在exe同级目录下。虽然解决办法一比较麻烦,但是还是推荐第一种方法,因为文件多了之后不用一个个的复制过去。
虽然有点啰嗦,还有些没有讲清楚!另外水平有限,还请谅解- - -
一定记得使用相对路径呀!!
个人网站:https://www.diaoyc.cn/