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 open读写文件实现脚本
Sep 06 Python
Python字典操作简明总结
Apr 13 Python
Python3.6正式版新特性预览
Dec 15 Python
python 数据的清理行为实例详解
Jul 12 Python
python RabbitMQ 使用详细介绍(小结)
Nov 08 Python
IntelliJ IDEA安装运行python插件方法
Dec 10 Python
Pycharm 设置默认头的图文教程
Jan 17 Python
python FTP批量下载/删除/上传实例
Dec 22 Python
django模型动态修改参数,增加 filter 字段的方式
Mar 16 Python
浅谈JupyterNotebook导出pdf解决中文的问题
Apr 22 Python
Python爬取微信小程序通用方法代码实例详解
Sep 29 Python
Python爬虫之Selenium多窗口切换的实现
Dec 04 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 array_walk() 数组函数
2011/07/12 PHP
Laravel框架实现利用中间件进行操作日志记录功能
2018/06/06 PHP
【消息提示组件】,兼容IE6/7&amp;&amp;FF2
2007/09/04 Javascript
Jquery Ajax学习实例5 向WebService发出请求,返回泛型集合数据的异步调用
2010/03/17 Javascript
Javascript倒计时页面跳转实例小结
2013/09/11 Javascript
js创建表单元素并使用submit进行提交
2014/08/14 Javascript
NodeJS学习笔记之Connect中间件应用实例
2015/01/27 NodeJs
利用Angularjs实现幻灯片效果
2016/09/07 Javascript
jquery对Json的各种遍历方法总结(必看篇)
2016/09/29 Javascript
Javascript中常用类型的格式化方法小结
2016/12/26 Javascript
jQuery.parseHTML() 函数详解
2017/01/09 Javascript
canvas 绘制圆形时钟
2017/02/22 Javascript
Vue 全局loading组件实例详解
2018/05/29 Javascript
详解vue-router 命名路由和命名视图
2018/06/01 Javascript
React 组件渲染和更新的实现代码示例
2019/02/21 Javascript
详解在网页上通过JS实现文本的语音朗读
2019/03/28 Javascript
使用localStorage替代cookie做本地存储
2019/09/25 Javascript
微信小程序自定义组件components(代码详解)
2019/10/21 Javascript
vue实现信息管理系统
2020/05/30 Javascript
python如何保证输入键入数字的方法
2019/08/23 Python
python3 下载网络图片代码实例
2019/08/27 Python
python智联招聘爬虫并导入到excel代码实例
2019/09/09 Python
python 在右键菜单中加入复制目标文件的有效存放路径(单斜杠或者双反斜杠)
2020/04/08 Python
Python中关于logging模块的学习笔记
2020/06/03 Python
AmazeUI底部导航栏与分享按钮的示例代码
2020/08/18 HTML / CSS
ellesse美国官方商店:意大利高级运动服品牌
2019/10/29 全球购物
Java面试题及答案
2012/09/08 面试题
物流管理应届生求职信
2013/11/07 职场文书
前台领班岗位职责
2013/12/04 职场文书
《天游峰的扫路人》教学反思
2014/04/25 职场文书
法制宣传标语
2014/06/23 职场文书
对外汉语专业大学生职业生涯规划书
2014/10/11 职场文书
2015年安全月活动总结
2015/03/26 职场文书
青涩记忆观后感
2015/06/18 职场文书
详解Vue router路由
2021/11/20 Vue.js
python解析json数据
2022/04/29 Python