Marco Nie - python https://blog.niekun.net/category/py/ 使用 Cython 对 python 代码加密打包 https://blog.niekun.net/archives/Cython-python.html 2025-08-14T16:10:00+08:00 目前我在使用 cx_Freeze 对 python 程序打包成可执行文件,但是 cx_Freeze 的核心功能是将 Python 脚本、Python 解释器以及所有依赖的库文件打包到一个独立的可执行文件(如 Windows 下的 .exe 文件)或一个包含所有文件的目录中。打包后的文件中包含的是 Python 的字节码 .pyc 文件,这个文件是可以被反编译回近似的源代码的。通过使用 Cython 将 Python 源代码编译成 C 语言,然后再生成本地二进制文件(.pyd)。然后正常使用 cx_Freeze 打包,这样做可以极大地提高代码的保护级别,防止被轻易逆向。安装必要的 Python 包需要安装 Cython 和 Numpy,在终端或命令行中运行:pip install Cython numpy 安装 C/C++ 编译器Cython 将 Python 代码转换成 C 代码,但最终需要一个 C 编译器来将 C 代码编译成机器码。这是最关键的一步。对于 Windows 用户:访问 Visual Studio 下载页面:https://visualstudio.microsoft.com/zh-hans/downloads/。在 "Tools for Visual Studio" (所有下载 -> Visual Studio 工具) 中找到并下载 "Build Tools for Visual Studio"。运行安装程序,在 "工作负荷" 标签页中,勾选 "使用 C++ 的桌面开发"。点击安装。安装完成后,您可能需要重启电脑。对于 macOS 用户:打开终端并运行 xcode-select --install。这会安装苹果的命令行开发者工具,其中包含了 Clang 编译器。对于 Linux 用户 (例如 Ubuntu/Debian):打开终端并运行 sudo apt update && sudo apt install build-essential。修改 setup.py 文件如果项目目录结构如下:/my_project |-- main.py # 你的主程序文件 |-- /src # 你的其他模块目录 | |-- func1.py | |-- func2.py |-- setup.py # cx_Freeze 的配置文件根据以上目录结构,下面是一个配置文件示例:from cx_Freeze import setup, Executable import sys, os, io # ============================================================================= # Cython 自动化编译集成 # ============================================================================= try: from Cython.Build import cythonize from setuptools import Extension import numpy except ImportError: print("\n[错误] 缺少必要的库。请先安装 Cython 和 Numpy:") print("pip install Cython numpy") sys.exit(1) sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') # 修复非中文系统打包时报错 # 增加递归调用深度限制 sys.setrecursionlimit(1500) # 定义相关路径 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) ENTRY_POINT = "main.py" # 检查是否为打包命令 build_commands = {"build", "bdist_msi", "bdist_dmg", "bdist_mac"} is_building = any(cmd in sys.argv for cmd in build_commands) # --- Cython 编译配置 --- # 此函数会自动查找 src 目录下的所有 .py 文件并准备将它们编译 def find_extensions_to_compile(dir_path="src"): """Find all .py files to be compiled by Cython.""" extensions = [] # 添加 numpy 的头文件路径,这对于编译依赖 numpy/scipy 的代码至关重要 numpy_include = numpy.get_include() for root, dirs, files in os.walk(dir_path): for file in files: # 我们只编译 .py 文件,但跳过 __init__.py 文件 if file.endswith(".py") and file != "__init__.py": path = os.path.join(root, file) # 将文件路径转换为模块路径,例如 "src/library/function.py" -> "src.library.function" module_path = path.replace(os.sep, '.')[:-3] extensions.append( Extension( name=module_path, sources=[path], include_dirs=[numpy_include] # 包含 numpy 头文件 ) ) print(f"--- 找到 {len(extensions)} 个模块准备通过 Cython 编译...") return extensions # 仅在执行打包命令时才准备编译列表 extensions = [] if is_building: # 1. 编译 src 目录下的所有模块 extensions.extend(find_extensions_to_compile("src")) # 2. 明确地将 main.py 添加到编译列表 print(f"--- 添加入口文件 '{ENTRY_POINT}' 到编译列表...") main_extension = Extension( name="main", # 编译后的模块名 sources=[ENTRY_POINT], include_dirs=[numpy.get_include()] ) extensions.append(main_extension) # ============================================================================= # cx_Freeze 配置 # ============================================================================= # 安装依赖 build_exe_options = { "packages": [ ], "excludes": ["email"] + [ext.name for ext in extensions], # 排除 Cython 编译的模块 "include_files": [ ], "includes": [], # 性能优化选项 "optimize": 2, # 使用Python优化 "include_msvcr": False, # 不包含MSVC运行库 } # 基础设置 base = "Win32GUI" if sys.platform == "win32" else None directory_table = [ # ... ] shortcut_table = [ ( # ... ), ( # ... ), ] msi_data = {"Directory": directory_table, "Shortcut": shortcut_table} bdist_msi_options = { # ... } executables = [ Executable( "main.py", # 入口文件 依然调用 py 程序,cx_Freeze 会自动识别并使用加密后的文件 # ... ) ] # ============================================================================= # 清理函数 # ============================================================================= def cleanup_generated_files(): """查找并删除由 Cython 生成的所有 .c 文件。""" print("\n--- 正在运行清理程序:删除生成的 C 文件... ---") for root, dirs, files in os.walk(ROOT_DIR): # 避免进入不相关的目录 if 'myenv' in root or '.git' in root or 'build' in root or 'dist' in root: continue for file in files: if file.endswith('.c'): file_path = os.path.join(root, file) try: os.remove(file_path) print(f"--- 已删除: {file_path}") except OSError as e: print(f"--- 删除失败 {file_path}: {e}") # ============================================================================= # 执行打包 # ============================================================================= try: setup( # ... # 关键步骤:将找到的 .py 文件交给 Cythonize 进行编译 ext_modules=cythonize( extensions, compiler_directives={'language_level': "3"}, # 使用 Python 3 语法 quiet=True # 减少不必要的编译输出 ) if is_building else [], # ... ) finally: # 只有在执行打包命令时才运行清理 if is_building: cleanup_generated_files()运行打包命令打包即可,如:python setup.py bdist_msi 检查加密情况安装完成后,进入安装路径的 Lib/site-packages 文件夹,会看到加密后的 .pyd 程序文件。.pyd 文件是 Windows 上的二进制动态链接库,本质上和 .dll 文件一样。如果加密失败:会在这里看到 .pyc 文件或者甚至原始的 .py 文件。 使用虚拟环境 env 开发 python https://blog.niekun.net/archives/env-python.html 2024-07-01T10:17:13+08:00 使用虚拟环境进行Python开发有助于隔离项目的依赖,避免不同项目之间的库版本冲突。以下是如何创建和使用虚拟环境的详细步骤。Python 3.3 及以上版本自带 venv 模块,可以直接使用。使用 venv 创建虚拟环境创建虚拟环境在你的项目目录下,运行以下命令来创建一个虚拟环境,这将在项目目录下创建一个名为 myenv 的文件夹,其中包含虚拟环境的所有文件:python -m venv myenv 激活虚拟环境Windows:myenv\Scripts\activate macOS 和 Linux:source myenv/bin/activate 安装依赖在虚拟环境中,你可以使用 pip 来安装项目所需的库:pip install requests 安装的库将只会影响当前虚拟环境,而不会影响系统的 Python 环境或其他项目。冻结依赖为了确保你的项目依赖可以在其他环境中重现,你可以使用以下命令将当前环境的依赖写入 requirements.txt 文件:pip freeze > requirements.txt requirements.txt 文件将包含所有当前环境中的安装包及其版本信息。使用 requirements.txt 安装依赖在新的环境中,你可以使用 requirements.txt 文件来安装所需的所有依赖:pip install -r requirements.txt 退出虚拟环境当你完成工作时,可以通过以下命令退出虚拟环境:deactivate 使用虚拟环境进行Python开发可以有效地隔离项目依赖,避免版本冲突。通过创建和激活虚拟环境、安装依赖、冻结依赖并在新环境中重新安装依赖,可以确保你的项目在不同环境中具有一致的运行表现。 从源码编译安装 python https://blog.niekun.net/archives/1758.html 2020-09-21T16:35:00+08:00 从源码编译程序的好处是可以使用最新版本,下面介绍如何在 Linux 下编译安装 python 和 pip 环境。下载源码包python 官网:https://www.python.org/当前最新版是 3.8.5,在这个页面找到地址:https://www.python.org/downloads/release/python-385/下载 tgz 压缩包到本地并解压:cd /tmp wget https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tgz tar xvf Python-3.8.5.tgz环境安装编译需要安装一些依赖:apt install libffi-dev libgdbm-dev libsqlite3-dev libssl-dev zlib1g-dev 编译python 源码使用标准 GNU 编译系统,详细说明参考:https://blog.niekun.net/archives/883.html将 python 安装到 /opt 目录,先创建文件夹:mkdir /opt/python3.8.5 然后配置 configure:cd /tmp/Python-3.8.5 ./configure \ --prefix=/opt/python3.8.5 \ --enable-optimizations \没有错误提示的话就开始编译和安装:make make install 安装完成后测试执行:/opt/python3.8.5/bin/python3 --version 返回版本信息则安装完成。下面将可执行文件加入系统路径,创建软连接:ln -s /opt/python3.8.5/bin/python3 /usr/bin/python 测试运行:python --version 安装 pip源码编译安装的 python 不自带 pip,需要自己安装,可以使用 get-pip.py 脚本来安装。官网:https://pip.pypa.io/en/stable/installing/下载脚本到本地:curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py使用刚才安装的 python 执行脚本:/opt/python3.8.5/bin/python3 get-pip.py pip 的安装路径是 /opt/python3.8.5/bin/,测试命令:/opt/python3.8.5/bin/pip3 --version 返回版本信息则安装完成。添加软连接到系统路径:ln -s /opt/python3.8.5/bin/pip3 /usr/bin/pip 测试命令:pip --version 参考链接https://docs.rstudio.com/resources/install-python-source/ 使用 subprocess.check_output 执行cmd命令并返回结果到字符串 https://blog.niekun.net/archives/1753.html 2020-09-18T15:13:51+08:00 语法:subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False) 执行cmd命令并返回结果到字符串。用法:import subprocess output = check_output(["cat", "/etc/hostname"]).strip() print(output)以上脚本会执行 cat /etc/hostname 命令然后将结果赋值给 output 变量。strip() 可以将 string 的前后空格去掉。 argparse and struct in python https://blog.niekun.net/archives/1718.html 2020-08-14T11:20:39+08:00 https://docs.python.org/3/library/argparse.htmlhttps://docs.python.org/3/library/struct.html string <-> byte in python https://blog.niekun.net/archives/1688.html 2020-08-12T14:08:00+08:00 To transform a unicode string to a byte string in Python do this:>>> 'foo'.encode('utf_8') b'foo' To transform a byte string to a unicode string:>>> b'foo'.decode('utf_8') 'foo' To convert a string to bytes.data = "" #string data = "".encode() #bytes data = b"" #bytesTo convert bytes to a String.data = b"" #bytes data = b"".decode() #string data = str(b"") #string winreg 操作 Windows 注册表 in python https://blog.niekun.net/archives/1685.html 2020-08-12T13:56:00+08:00 https://docs.python.org/3/library/winreg.html#https://stackoverflow.com/questions/15128225/python-script-to-read-and-write-a-path-to-registryimport winreg REG_PATH = r"Control Panel\Mouse" def set_reg(name, value): try: winreg.CreateKey(winreg.HKEY_CURRENT_USER, REG_PATH) registry_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, REG_PATH, 0, winreg.KEY_WRITE) winreg.SetValueEx(registry_key, name, 0, winreg.REG_SZ, value) winreg.CloseKey(registry_key) return True except WindowsError: return False def get_reg(name): try: registry_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, REG_PATH, 0, winreg.KEY_READ) value, regtype = winreg.QueryValueEx(registry_key, name) winreg.CloseKey(registry_key) return value except WindowsError: return None #Example MouseSensitivity #Read value print (get_reg('MouseSensitivity')) #Set Value 1/20 (will just write the value to reg, the changed mouse val requires a win re-log to apply*) set_reg('MouseSensitivity', str(10)) #*For instant apply of SystemParameters like the mouse speed on-write, you can use win32gui/SPI #http://docs.activestate.com/activepython/3.4/pywin32/win32gui__SystemParametersInfo_meth.html 使用 opencv 处理图像 https://blog.niekun.net/archives/1684.html 2020-08-07T11:37:51+08:00 安装:https://pypi.org/project/opencv-python/使用:https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_setup/py_table_of_contents_setup/py_table_of_contents_setup.html示例:https://www.askaswiss.com/2016/01/how-to-create-pencil-sketch-opencv-python.html打包 exe:https://pypi.org/project/auto-py-to-exe/ 使用 TelegramBot 键盘 InlineKeyboardButton 提示 BUTTON_DATA_INVALID 报错原因分析 https://blog.niekun.net/archives/880.html 2020-02-01T18:06:06+08:00 今天在测试 telegram Bot 的时候,发现 keyboard 不能正确弹出来,后台查看发现报错了,提示 Bad Request: BUTTON_DATA_INVALID反复检查代码没有发现语法错误,查找之后了解到 InlineKeyboardButton 响应后返回的 Callback Data 有大小限制,最大64位:的确我想返回的内容长度的确超过了大小限制,优化源码后问题解决了。参考链接:https://core.telegram.org/bots/api#inlinekeyboardbuttonhttps://stackoverflow.com/questions/46389040/inlinekeyboardbutton-are-limited-in-inlinekeyboardmarkup-telegram-bot-c-sharp python 常用语法收集 https://blog.niekun.net/archives/438.html 2019-10-17T14:52:00+08:00 在我使用过程中遇到的常用语法,这里做一些记录。os.system()可以用来运行终端命令:import os os.system('date') ----------------------- The current date is: 10/17/2019 Thu glob用来将匹配的文件放入数组:import glob import os CWD = os.getcwd()#当前目录路径 for name in glob.glob(CWD+'/*'): print(name)以上输出当前目录下所有文件的文件名。for name in glob.glob(CWD+'/file?.txt'): print(name)以上输出 filea.txt, fileb.txt filec.txt 等文件名。可以使用类似正则表达式的方式匹配文件名:glob.glob(CWD+'/*[12].*') 从python3.5开始,支持使用一下方法进行递归搜索目录内文件及文件夹:for name in glob.glob(CWD+'/**/*', recursive=True): print(name)以上会输出目录内文件及子文件夹内文件。split()字符串分割:按空格分割,注意两个部分之间的空格可以是1个或多个,不影响分割效果:txt = "welcome to the jungle" x = txt.split()将 txt 字符串按空格来分成4个部分,x 是数组。分割成设定的个数:txt = "welcome to the jungle" x = txt.split(' ', 1)输出结果:x = ['welcome', 'to the jungle']按特定字符分割:txt = "apple#banana#cherry#orange" x = txt.split("#", 1)输出结果:x = ['apple', 'banana#cherry#orange']next()用于 iterator 的顺序提取。mylist = iter(["apple", "banana", "cherry"]) x = next(mylist) print(x) y = next(mylist) print(x) z = next(mylist) print(x)输出结果:x = 'apple' y = 'banana' z = 'cherry'format()用于字符串内的赋值:print ("{}, A computer science portal for geeks".format("GeeksforGeeks"))输出:GeeksforGeeks, A computer science portal for geeks多个输入参数:print ("Hi ! My name is {} and I am {} years old" .format("User", 19)) 带索引的多参数输入:print("Every {3} should know the use of {2} {1} programming and {0}" .format("programmer", "Open", "Source", "Operating Systems")) 输出结果:Every Operating Systems should know the use of Source Open programming and programmerstrip()删除字符串前和后的空格:txt = " banana " x = txt.strip()输出:x = 'banana'删除字符串前和后的自定义字符:txt = ",,,,,rrttgg.....banana....rrr" x = txt.strip(",.grt")输出: x = 'banana'