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'