吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6998|回复: 70
收起左侧

[Windows] py程序一键打包,自动安装支持库

  [复制链接]
小亮爱红燕 发表于 2025-7-16 17:19
之前找了几个打包程序 一直弹出支持库未安装 可是明明安装了  于是自己折腾了一个  支持自定义图标等 老鸟勿喷 新手     
附上地址:通过网盘分享的文件:一键打包 自动安装支持库.exe 链接: https://pan.baidu.com/s/1yC_zsaGuT4GQx87dKCtIpA?pwd=52pj 提取码: 52pj --来自百度网盘超级会员v4的分享

自动检测,安装支持库

自动检测,安装支持库

打包主页面

打包主页面

免费评分

参与人数 9吾爱币 +7 热心值 +7 收起 理由
lyqwertyuiop + 1 感谢分享。有两个可以修正的地方:一是加上隐藏cmd窗口;二是输出路径加上 ...
傲视无极 + 1 谢谢@Thanks!
Gogoing丶 + 1 + 1 我很赞同!
cdchj + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
yjjcm321 + 1 我很赞同!
thornjay + 1 + 1 我很赞同!
lbj528811 + 1 谢谢@Thanks!
10830 + 1 + 1 谢谢@Thanks!
仰望星空43 + 1 + 1 都加给你,升级下 32bit和64bit

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

仰望星空43 发表于 2025-7-18 20:42
能不能支持 分别打包 32位程序和64位程序
谢谢
 楼主| 小亮爱红燕 发表于 2025-7-16 17:20
链接:链接: https://pan.baidu.com/s/1yC_zsaGuT4GQx87dKCtIpA?pwd=52pj 提取码: 52pj --来自百度网盘超级会员v4的分享
dj215 发表于 2025-8-3 21:34
Wewill 发表于 2025-8-2 11:03
链接有问题,转存总是失败,谁能转个蓝盘。好东西别放毒盘,他不配

蓝盘没号,给你转一个夸克吧·
链接:https://pan.quark.cn/s/3c979e656978?pwd=1Jsc
提取码:1Jsc
 楼主| 小亮爱红燕 发表于 2025-7-22 08:12
字节跳动 发表于 2025-7-21 21:20
楼主,这个源代码有没有,打开有个黑屏,打包的时候可以把这个黑屏去掉的。

import os
import sys
import subprocess
import tkinter as tk
from tkinter import filedialog, messagebox, ttk


class PyPackagerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Python打包工具")
        self.root.geometry("650x550")  # 稍微加大窗口以适应新控件

        # 变量定义
        self.script_path = tk.StringVar()
        self.icon_path = tk.StringVar()
        self.output_dir = tk.StringVar(value="dist")
        self.app_name = tk.StringVar()
        self.onefile = tk.BooleanVar(value=True)
        self.hidden_imports = tk.StringVar()
        self.exclude_modules = tk.StringVar()
        self.additional_data = tk.StringVar()
        self.semi_include = tk.BooleanVar(value=True)
        self.architecture = tk.StringVar(value="64bit")  # 默认64位

        self.create_widgets()

    def create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 脚本选择
        ttk.Label(main_frame, text="Python脚本:").grid(row=0, column=0, sticky=tk.W, pady=2)
        script_frame = ttk.Frame(main_frame)
        script_frame.grid(row=0, column=1, sticky=tk.EW, pady=2)
        ttk.Entry(script_frame, textvariable=self.script_path, width=40).pack(side=tk.LEFT, fill=tk.X, expand=True)
        ttk.Button(script_frame, text="浏览...", command=self.browse_script).pack(side=tk.LEFT, padx=5)

        # 图标选择
        ttk.Label(main_frame, text="图标文件(.ico):").grid(row=1, column=0, sticky=tk.W, pady=2)
        icon_frame = ttk.Frame(main_frame)
        icon_frame.grid(row=1, column=1, sticky=tk.EW, pady=2)
        ttk.Entry(icon_frame, textvariable=self.icon_path, width=40).pack(side=tk.LEFT, fill=tk.X, expand=True)
        ttk.Button(icon_frame, text="浏览...", command=self.browse_icon).pack(side=tk.LEFT, padx=5)

        # 输出目录
        ttk.Label(main_frame, text="输出目录:").grid(row=2, column=0, sticky=tk.W, pady=2)
        output_frame = ttk.Frame(main_frame)
        output_frame.grid(row=2, column=1, sticky=tk.EW, pady=2)
        ttk.Entry(output_frame, textvariable=self.output_dir, width=40).pack(side=tk.LEFT, fill=tk.X, expand=True)
        ttk.Button(output_frame, text="浏览...", command=self.browse_output).pack(side=tk.LEFT, padx=5)

        # 应用名称
        ttk.Label(main_frame, text="应用名称:").grid(row=3, column=0, sticky=tk.W, pady=2)
        ttk.Entry(main_frame, textvariable=self.app_name).grid(row=3, column=1, sticky=tk.EW, pady=2)

        # 打包方式
        ttk.Label(main_frame, text="打包方式:").grid(row=4, column=0, sticky=tk.W, pady=2)
        ttk.Radiobutton(main_frame, text="单个可执行文件", variable=self.onefile, value=True).grid(row=4, column=1,
                                                                                                   sticky=tk.W)
        ttk.Radiobutton(main_frame, text="目录形式", variable=self.onefile, value=False).grid(row=5, column=1,
                                                                                              sticky=tk.W)

        # 架构选择 (新增)
        ttk.Label(main_frame, text="程序架构:").grid(row=6, column=0, sticky=tk.W, pady=2)
        arch_frame = ttk.Frame(main_frame)
        arch_frame.grid(row=6, column=1, sticky=tk.W, pady=2)
        ttk.Radiobutton(arch_frame, text="64位", variable=self.architecture, value="64bit").pack(side=tk.LEFT)
        ttk.Radiobutton(arch_frame, text="32位", variable=self.architecture, value="32bit").pack(side=tk.LEFT, padx=10)

        # 包含模式
        ttk.Label(main_frame, text="包含模式:").grid(row=7, column=0, sticky=tk.W, pady=2)
        ttk.Radiobutton(main_frame, text="半包含(排除大型库)", variable=self.semi_include, value=True).grid(row=7,
                                                                                                            column=1,
                                                                                                            sticky=tk.W)
        ttk.Radiobutton(main_frame, text="完全包含所有依赖", variable=self.semi_include, value=False).grid(row=8,
                                                                                                           column=1,
                                                                                                           sticky=tk.W)

        # 高级选项
        advanced_frame = ttk.LabelFrame(main_frame, text="高级选项", padding=(10, 5))
        advanced_frame.grid(row=9, column=0, columnspan=2, sticky=tk.EW, pady=10)

        ttk.Label(advanced_frame, text="隐藏导入:").grid(row=0, column=0, sticky=tk.W, pady=2)
        ttk.Entry(advanced_frame, textvariable=self.hidden_imports, width=40).grid(row=0, column=1, sticky=tk.EW,
                                                                                   pady=2)

        ttk.Label(advanced_frame, text="排除模块:").grid(row=1, column=0, sticky=tk.W, pady=2)
        ttk.Entry(advanced_frame, textvariable=self.exclude_modules, width=40).grid(row=1, column=1, sticky=tk.EW,
                                                                                    pady=2)

        ttk.Label(advanced_frame, text="额外数据文件:").grid(row=2, column=0, sticky=tk.W, pady=2)
        ttk.Entry(advanced_frame, textvariable=self.additional_data, width=40).grid(row=2, column=1, sticky=tk.EW,
                                                                                    pady=2)
        ttk.Label(advanced_frame, text="格式: 源路径:目标路径;多个用分号分隔", foreground="gray").grid(row=3, column=1,
                                                                                                       sticky=tk.W)

        # 操作按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=10, column=0, columnspan=2, pady=10)
        ttk.Button(button_frame, text="开始打包", command=self.package).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="退出", command=self.root.quit).pack(side=tk.LEFT, padx=5)

        # 日志输出
        ttk.Label(main_frame, text="日志输出:").grid(row=11, column=0, sticky=tk.W, pady=2)
        self.log_text = tk.Text(main_frame, height=8, state=tk.DISABLED)
        self.log_text.grid(row=12, column=0, columnspan=2, sticky=tk.EW)
        scrollbar = ttk.Scrollbar(main_frame, orient=tk.VERTICAL, command=self.log_text.yview)
        scrollbar.grid(row=12, column=2, sticky=tk.NS)
        self.log_text.configure(yscrollcommand=scrollbar.set)

        # 配置网格权重
        main_frame.columnconfigure(1, weight=1)
        main_frame.rowconfigure(12, weight=1)

    def browse_script(self):
        path = filedialog.askopenfilename(
            title="选择Python脚本",
            filetypes=[("Python文件", "*.py"), ("所有文件", "*.*")]
        )
        if path:
            self.script_path.set(path)
            if not self.app_name.get():
                self.app_name.set(os.path.splitext(os.path.basename(path))[0])

    def browse_icon(self):
        path = filedialog.askopenfilename(
            title="选择图标文件",
            filetypes=[("图标文件", "*.ico"), ("所有文件", "*.*")]
        )
        if path:
            self.icon_path.set(path)

    def browse_output(self):
        path = filedialog.askdirectory(title="选择输出目录")
        if path:
            self.output_dir.set(path)

    def log(self, message):
        self.log_text.configure(state=tk.NORMAL)
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
        self.log_text.configure(state=tk.DISABLED)
        self.root.update()

    def package(self):
        if not self.script_path.get():
            messagebox.showerror("错误", "请先选择要打包的Python脚本!")
            return

        try:
            # 检查PyInstaller是否安装
            try:
                import pyinstaller
            except ImportError:
                self.log("PyInstaller未安装,正在自动安装...")
                subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
                self.log("PyInstaller安装完成")

            # 准备打包命令
            cmd = ["pyinstaller"]

            if self.onefile.get():
                cmd.append("--onefile")
            else:
                cmd.append("--onedir")

            if self.icon_path.get():
                cmd.extend(["--icon", self.icon_path.get()])

            if self.app_name.get():
                cmd.extend(["--name", self.app_name.get()])

            # 添加架构选择 (新增)
            if self.architecture.get() == "32bit":
                if sys.platform == "win32":
                    # Windows系统下指定32位Python路径
                    python_32bit = self.find_32bit_python()
                    if python_32bit:
                        cmd.insert(0, python_32bit)
                        self.log(f"使用32位Python: {python_32bit}")
                    else:
                        messagebox.showwarning("警告", "未找到32位Python,将使用当前Python环境")
                else:
                    messagebox.showwarning("警告", "非Windows系统下32位打包可能无效")

            if self.hidden_imports.get():
                for imp in self.hidden_imports.get().split(','):
                    if imp.strip():
                        cmd.extend(["--hidden-import", imp.strip()])

            if self.exclude_modules.get():
                for mod in self.exclude_modules.get().split(','):
                    if mod.strip():
                        cmd.extend(["--exclude-module", mod.strip()])

            if self.additional_data.get():
                for item in self.additional_data.get().split(';'):
                    if item.strip():
                        src_dest = item.split(':', 1)
                        if len(src_dest) == 2:
                            cmd.extend(["--add-data", f"{src_dest[0].strip()}{os.pathsep}{src_dest[1].strip()}"])

            if self.semi_include.get():
                # 半包含模式 - 不打包某些大型库
                cmd.extend(["--exclude-module", "numpy"])
                cmd.extend(["--exclude-module", "pandas"])
                cmd.extend(["--exclude-module", "matplotlib"])
                cmd.extend(["--exclude-module", "scipy"])
                cmd.extend(["--exclude-module", "sklearn"])
                cmd.extend(["--exclude-module", "tensorflow"])
                cmd.extend(["--exclude-module", "torch"])

            cmd.append("--clean")
            cmd.append(self.script_path.get())

            self.log("开始打包...")
            self.log(f"目标架构: {self.architecture.get()}")
            self.log("执行命令: " + " ".join(cmd))

            # 执行打包
            process = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                universal_newlines=True,
                creationflags=subprocess.CREATE_NO_WINDOW if sys.platform == "win32" else 0
            )

            # 实时输出日志
            for line in process.stdout:
                self.log(line.strip())

            process.wait()

            if process.returncode == 0:
                self.log("打包成功完成!")
                messagebox.showinfo("完成", "打包成功完成!")
            else:
                self.log("打包失败!")
                messagebox.showerror("错误", "打包过程中出现错误!")

        except Exception as e:
            self.log(f"发生错误: {str(e)}")
            messagebox.showerror("错误", f"打包失败: {str(e)}")

    def find_32bit_python(self):
        """尝试查找32位Python解释器"""
        # 检查当前Python是否是32位
        if sys.maxsize <= 2 ** 32:
            self.log("当前Python已经是32位")
            return None
        
        possible_paths = [
            r"C:\Python36-32\python.exe",  # Python 3.6
            r"C:\Python37-32\python.exe",  # Python 3.7
            r"C:\Python38-32\python.exe",  # Python 3.8
            r"C:\Python39-32\python.exe",  # Python 3.9
            r"C:\Python310-32\python.exe",  # Python 3.10
            r"C:\Python311-32\python.exe",  # Python 3.11
            r"C:\Python312-32\python.exe",  # Python 3.12
            r"C:\Program Files (x86)\Python\python.exe",
            r"C:\Program Files (x86)\Python36-32\python.exe",
            r"C:\Program Files (x86)\Python37-32\python.exe",
            r"C:\Program Files (x86)\Python38-32\python.exe",
            r"C:\Program Files (x86)\Python39-32\python.exe",
            r"C:\Program Files (x86)\Python310-32\python.exe",
            r"C:\Program Files (x86)\Python311-32\python.exe",
            r"C:\Program Files (x86)\Python312-32\python.exe",
        ]

        for path in possible_paths:
            if os.path.exists(path):
                # 验证是否是32位Python
                try:
                    output = subprocess.check_output([path, "-c", "import sys; print(sys.maxsize <= 2**32)"])
                    if output.decode().strip() == "True":
                        return path
                except:
                    continue

        return None


def main():
    root = tk.Tk()
    app = PyPackagerApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()
FMTpoty 发表于 2025-7-19 23:37
感谢分享
inbremen 发表于 2025-7-20 00:25
仰望星空43 发表于 2025-7-18 20:42
能不能支持 分别打包 32位程序和64位程序
谢谢

同求同求同求同求同求同求同求同求同求同求同求同求同求同求
 楼主| 小亮爱红燕 发表于 2025-7-20 08:23
inbremen 发表于 2025-7-20 00:25
同求同求同求同求同求同求同求同求同求同求同求同求同求同求

好的  我将尽快更新
xiguapi66 发表于 2025-7-20 14:36
感谢大佬,下载使用,对于我这样的小白来说,可以方便打包
77153575 发表于 2025-7-20 14:51
感谢 下载个用用
dxy796 发表于 2025-7-20 15:01
上次问了,没打包,下载自动打包试试
kimiaki 发表于 2025-7-20 15:14
感谢分享,刚好需要
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-3-18 03:06

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表