Python封装成可带参数的EXE安装包实例


Posted in Python onAugust 24, 2019

最近有一个小项目,有如下的需求:

将某几个源码文件夹进行打包,文件夹内有py文件、dll文件、exe文件等各种文件类型

打包生成的安装包,在进行安装的时候,应该能够带有参数,对配置文件进行修改配置

安装过程中,可以配置系统环境变量

能够检测环境,提示安装依赖包

整个过程要可以自动化,能够大量部署

综合考虑后,决定以下几个步骤完成:

用setup.py将源码文件夹都打包成msi安装包,这样可以使用msiexec进行静默安装

setup.py可以提示用户安装依赖包,否则安装失败

再编写一个py文件,用来静默安装msi安装包,并配置系统环境变量,接受安装参数去修改配置文件的属性

最后使用pyinstaller将所有都打包成exe文件

先来编写setup.py文件:

# coding=utf-8
from distutils.core import setup
import os
 
 
def get_all_dir(path):
  """
    获取指定路径下的所有文件
  """
  all_file = []
  for dirpath, dirnames, filenames in os.walk(path):
    for filename in filenames:
      all_file.append(dirpath)
  return all_file
 
 
if __name__ == '__main__':
  all_file = get_all_dir('A') + get_all_dir('B') # 获取相对路径下A和B两个文件夹下的所有文件
  setup(name='Example', # 所要安装的软件名
     version="1.0", # 版本
     description="This is example", # 对所安装软件的描述
     author="author", # 作者
     author_email='my email', # 邮箱
     packages=all_file, # 要打包的文件
     package_data={'': ['*.*']}, # 所有文件类型都打包
     classifiers=[
       'Development Status :: 5 - Production/Stable',
       'Operating System :: Microsoft :: Windows',
       'Natural Language :: Chinese (Simplified)',
       'Programming Language :: Python',
       'Programming Language :: Python :: 2.7',
       'Topic :: Software Development :: Libraries :: Python Modules'
     ], # 需要参照https://pypi.python.org/pypi?%3Aaction=list_classifiers,用于发布在PYPI上
     install_requires=[
       'pyserial==3.2.1'
     ], # 依赖包,如果没有安装,会提示缺少,并安装失败
     )

然后打开setup.py所在目录,并将A和B两个文件夹复制过来

打开dos窗口,并运行

python setup.py bdist_msi

运行结果如下图:

build我们不关注,直接看dist,里面有一个Example-1.0.win32.msi,这就是我们生成的msi安装包。

我们再编写一个Example.py用来配置系统环境变量,并接受安装参数修改配置文件:

# coding=utf-8
import os
import sys
import subprocess
 
config_file = r"C:\Python27\Lib\site-packages\B\lib\configuration\config.cfg"
 
import sys
from subprocess import check_call
 
 
### 设置系统环境变量所需代码
if sys.hexversion > 0x03000000:
  import winreg
else:
  import _winreg as winreg
 
ENV_VARAIABLE = 'Result_Path'
 
 
class Win32Environment:
  def __init__(self, scope):
    assert scope in ('user', 'system')
    self.scope = scope
    if scope == 'user':
      self.root = winreg.HKEY_CURRENT_USER
      self.subkey = 'Environment'
    else:
      self.root = winreg.HKEY_LOCAL_MACHINE
      self.subkey = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
 
  def getenv(self, name):
    key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_READ)
    try:
      value, _ = winreg.QueryValueEx(key, name)
    except WindowsError:
      value = ''
    return value
 
  def setenv(self, name, value):
    key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_ALL_ACCESS)
    winreg.SetValueEx(key, name, 0, winreg.REG_EXPAND_SZ, value)
    winreg.CloseKey(key)
    try:
      check_call('''\
  "%s" -c "import win32api, win32con; assert win32api.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')"''' % sys.executable)
    except Exception as e:
      print e.message
 
 
### 设置系统环境变量所需代码 end
 
 
def search_content(str, lists):
  """
    查找str是否存在于lists中,不存在就退出程序
  """
  for i in lists:
    if str in i:
      return lists.index(i)
  print "The section not found"
  os._exit(1)
 
 
def run_command_line(command_line):
  """
    运行command line
  """
  print("run:" + command_line)
  p = subprocess.Popen(command_line, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  (stdout, stderr) = p.communicate()
  try:
    print("stdout:" + stdout)
    print("stderr:" + stderr)
  except:
    pass
 
 
def main():
  # 静默安装MSI安装包
  run_command_line("msiexec /i " + sys.path[0] + r"\Example-1.0.win32.msi /qb REBOOT=SUPPRESS")
 
  # 接受参数
  section = sys.argv[1]
  attribute = sys.argv[2]
  change = sys.argv[3]
 
  # 读取配置文件内容
  file = open(config_file, 'r')
  content = file.readlines()
  file.close()
 
  # 修改配置文件的某个属性值
  index = search_content(section, content)
  is_change = False
  for change_str in content[index + 1:]:
    if "[" in change_str:
      if not is_change:
        print "Property does not exist or not in this section"
      break
    if attribute in change_str:
      content[content.index(change_str)] = change_str[:change_str.index("=") + 1] + change + "\n"
      is_change = True
      break
 
  # 把修改后的内容写入配置文件
  file = open(config_file, 'w')
  for i in content:
    file.write(i)
  file.close()
 
 
if __name__ == "__main__":
  # 如果没有参数,就默认直接安装MSI安装包
  # 如果有参数,但是参数个数不足,直接报错退出
  if len(sys.argv) == 1 and sys.argv[0] == "commonlib.exe":
    run_command_line("msiexec /i " + sys.path[0] + r"\Example-1.0.win32.msi /qb REBOOT=SUPPRESS")
  elif len(sys.argv) != 4:
    print "Usage: commonlib.py <section> <section-attribute> <attribute-value>"
    sys.exit(1)
  else:
    main()
 
  # 设置系统环境变量
  e = Win32Environment(scope="system")
  e.setenv(ENV_VARAIABLE, r'C:\Local')
  print "Setup Success!"

现在我们用Pyinstaller来进行最后的打包。

先看一个重要的文件Example.spec

spec文件是Pyinstaller打包成EXE的配置文件,是自动生成的,这里我直接拿以前的进行修改,刚开始没有的,可以直接随便运行一次Pyinstaller来获得,直接复制我的也可以。

# -*- mode: python -*-
 
block_cipher = None
 
 
a = Analysis(['Example.py'], # 主要打包的主py文件
       pathex=['C:\\Users\\abc\\Documents'], # 打包路径
       binaries=None,
       datas=None,
       hiddenimports=[],
       hookspath=[],
       runtime_hooks=[],
       excludes=[],
       win_no_prefer_redirects=False,
       win_private_assemblies=False,
       cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
       cipher=block_cipher)
a.datas+= [('Exmaple.msi', r'C:\Users\abc\Documents\Example-1.0.win32.msi', 'DATA'),]# 附加文件,打包时加入到EXE文件中,让我们可以在py文件中调用
exe = EXE(pyz,
     a.scripts,
     a.binaries,
     a.zipfiles,
     a.datas, # 打包文件列表
     name='examlpe',# exe文件的名字
     debug=False,
     strip=False,
     upx=True,
     console=True )

打开Example.spec所在的路径,复制MSI安装包到这里,在dos窗口中运行

pyinstaller Example.spec

运行成功后,会生成build和dist两个文件夹,我们依然只看dist文件夹,里面example.exe就是我们所需要的

以上这篇Python封装成可带参数的EXE安装包实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python多线程编程(七):使用Condition实现复杂同步
Apr 05 Python
python中for语句简单遍历数据的方法
May 07 Python
解决PyCharm中光标变粗的问题
Aug 05 Python
Python+tkinter使用80行代码实现一个计算器实例
Jan 16 Python
解决python3运行selenium下HTMLTestRunner报错的问题
Dec 27 Python
解决python gdal投影坐标系转换的问题
Jan 17 Python
python中线程和进程有何区别
Jun 17 Python
Python调用jar包方法实现过程解析
Aug 11 Python
Python Pivot table透视表使用方法解析
Sep 11 Python
python读取excel数据绘制简单曲线图的完整步骤记录
Oct 30 Python
Python结合百度语音识别实现实时翻译软件的实现
Jan 18 Python
使用Djongo模块在Django中使用MongoDB数据库
Jun 20 Python
python识别文字(基于tesseract)代码实例
Aug 24 #Python
python图片二值化提高识别率代码实例
Aug 24 #Python
关于Python形参打包与解包小技巧分享
Aug 24 #Python
python-序列解包(对可迭代元素的快速取值方法)
Aug 24 #Python
对python中的装包与解包实例详解
Aug 24 #Python
Python3进制之间的转换代码实例
Aug 24 #Python
Python实现朴素贝叶斯的学习与分类过程解析
Aug 24 #Python
You might like
同一空间绑定多个域名而实现访问不同页面的PHP代码
2006/12/06 PHP
深入PHP运行环境配置的详解
2013/06/04 PHP
PHP中nowdoc和heredoc使用需要注意的一点
2014/03/21 PHP
PHP调用Linux命令权限不足问题解决方法
2015/02/07 PHP
php实现两个数组相加的方法
2015/02/17 PHP
微信开发之网页授权获取用户信息(二)
2016/01/08 PHP
thinkPHP5.0框架安装教程
2017/03/25 PHP
Laravel框架实现定时发布任务的方法
2018/08/16 PHP
鼠标经过的文本框textbox变色
2009/05/21 Javascript
jquery中实现标签切换效果的代码
2011/03/01 Javascript
jQuery阻止事件冒泡具体实现
2013/10/11 Javascript
jquery中交替点击事件的实现代码
2014/02/14 Javascript
jQuery如何防止这种冒泡事件发生
2015/02/27 Javascript
基于jquery实现的树形菜单效果代码
2015/09/06 Javascript
JavaScript简单实现合并两个Json对象的方法示例
2017/10/16 Javascript
关于Webpack dev server热加载失败的解决方法
2018/02/22 Javascript
vue-prop父组件向子组件进行传值的方法
2018/03/01 Javascript
Nodejs异步回调之异常处理实例分析
2018/06/22 NodeJs
Vue.js实现tab切换效果
2019/07/24 Javascript
python调用xlsxwriter创建xlsx的方法
2018/05/03 Python
使用Python写一个量化股票提醒系统
2018/08/22 Python
Python3中关于cookie的创建与保存
2018/10/21 Python
Python简单获取二维数组行列数的方法示例
2018/12/21 Python
利用Python自动化操作AutoCAD的实现
2020/04/01 Python
Python requests接口测试实现代码
2020/09/08 Python
如何用Python进行时间序列分解和预测
2021/03/01 Python
阿迪达斯比利时官方商城:adidas比利时
2016/10/10 全球购物
Kathmandu澳洲户外商店:新西兰户外运动品牌
2017/11/12 全球购物
日本最大的旅游网站:Rakuten Travel(乐天旅游)
2018/08/02 全球购物
阿玛尼美妆英国官网:Giorgio Armani Beauty英国
2019/03/28 全球购物
宿舍打麻将检讨书
2014/01/24 职场文书
黄河象教学反思
2014/02/10 职场文书
元宵节寄语大全
2015/02/27 职场文书
《牧场之国》教学反思
2016/02/22 职场文书
大学生自我鉴定怎么写
2019/05/07 职场文书
nginx共享内存的机制详解
2022/03/21 Servers