社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

【Python开个脑洞】如何做一个运营小姐姐爱不释手的解压缩小工具

蚂蚁学Python • 4 年前 • 637 次点击  

此前接单做了一个批量解压缩小工具后脑洞大开,打算给运营小姐姐们做一个小工具,解放一下她们时间,同时享受一下小姐姐们的崇拜的眼神......好吧,话不多说,咱们直接开始:

使用场景与需求分析

解释一下使用场景:公司为了数据安全,给所有下载的数据压缩包设置了一个6位数字密码,密码使用短信发送到下载人指定手机上。如果一次下载单个文件,那解压缩很简单,但是如果下载的文件数量较多,一个一个压缩包与密码短信进行配对那就有点让人烦躁了。

因此,小工具要实现的需求就是:能够批量的将压缩包与密码短信文本进行自动匹配,将匹配到的压缩包进行解压缩;同时,要实现一个交互界面,并打包成可执行文件。


分步实现

有了需求,那么就是一步一步实现它:

  1. 要打包成exe可执行文件,可以使用pyinstaller进行打包,若要打包文件最小,需要创建一个虚拟环境,安装最少的第三方包,因此,使用pycharm进行虚拟环境创建,并安装需要使用到的包。
pycharm创建虚拟环境

安装需要使用到的包:pyinstaller、pyzipper(zipfile不支持我司的压缩包格式解压)

安装需要的包
  1. 实现交互界面,使用了tkinter
# -*- coding: utf-8 -*-
# @author: Lin Wei
# @contact: 580813@qq.com
# @time: 2021/11/23 10:35
# @file: unzip_file.py
# @desc:

import tkinter as tk
from tkinter import filedialog
from extract_files import ExtractFiles  # 需要自行实现的方法

# 定义一个tk窗口
wd = tk.Tk()
wd.title('解压小程序V1.0')
wd.geometry('800x500')

# 设置选择解压缩文件包所在路径的按钮及功能
# 定义选择压缩包的路径为tk的字符串变量
unzip_files_path = tk.StringVar()


def get_files_path():
    """
    运行函数将设置路径
    """

    unzip_files_path.set(filedialog.askdirectory())


# 定义压缩包路径的标签,并设置所在位置
files_path_label = tk.Label(wd, text='需要批量解压的文件路径:')
files_path_label.grid(row=0, column=0)
# 定义压缩包路径的输入框,并设置所在位置,其中输入框所显示内容为tk变量unzip_files_path
files_path_entry = tk.Entry(wd, textvariable=unzip_files_path, width=80)
files_path_entry.grid(row=0, column=1)
# 定义压缩包路径的选择按钮,并设置所在位置,其中按钮点击的命令为get_unzip_files_path
files_path_button = tk.Button(wd, text='选择路径', command=get_files_path)
files_path_button.grid(row=0, column=2)


# 设置解压缩密码文本的text框,同时实现可输入或选择txt文件进行读取的功能
# 定义选择解压缩密码文本文件的函数
def choose_password_text():
    password_text_path = filedialog.askopenfilename(
        title='请选择解压缩的密码文本',
        initialdir='/',
        filetypes=[('文本文档''*.txt')]
    )
    if password_text_path:
        text = 'TXT文件错误或编码非utf-8和ansi,请在文本框中直接输入密码文本'
        for code in ['utf-8''ansi']:
            try:
                with open(password_text_path, 'r', encoding=code) as fin:
                    text = fin.read()
                break
            except Exception:
                pass
        password_text_text.delete(1.0'end')
        password_text_text.insert(1.0, text)


info_mes = """这里写上短信文本的示例,作为提示"""

# 定义密码文本的标签,并设置所在位置
password_text_label = tk.Label(wd, text='解压缩文件的密码短信文本:')
password_text_label.grid(row=1 , column=0)
# 定义密码文本的输入框,并设置所在位置,其中输入框所显示内容为tk变量password_text
password_text_text = tk.Text(wd, height=15)
password_text_text.insert(1.0f'直接在此粘贴短信文本,示例如下:\n{info_mes}\n(可以多条)\n也可以点击左侧按钮读取存放在TXT文件中的短信文本')
password_text_text.grid(row=1, column=1, sticky=tk.E+tk.W+tk.N)
# 定义压缩包路径的选择按钮,并设置所在位置,其中按钮点击的命令为choose_path1
password_text_button = tk.Button(wd, text='选择密码文件', command=choose_password_text)
password_text_button.grid(row=1, column=2)


# 设置解压运行按钮以及解压缩的方法
def run_unzip():
    # 从路径选择框里获取路径文本
    root_path = files_path_entry.get()
    # 从密码输入框里获取密码文本
    password_text = password_text_text.get(1.0'end')
    # 清除执行情况框中的全部内容
    run_message_text.delete(1.0, tk.END)
    # 运行解压缩程序
    obj = ExtractFiles(root_path, password_text)
    obj.get_all_zip_files()
    obj.parse_password()
    obj.matching()
    obj.do_extract()
    # 往执行情况框里添加内容
    # 添加成功解压缩的记录
    run_message_text.insert(tk.END, '\n'.join([f'成功解压{x}' for x in obj.success_files_list]) + '\n')
    # 添加解压失败的记录(注:有匹配到密码,但解压缩失败)
    run_message_text.insert(tk.END, '\n'.join([f'解压失败{x}' for x in obj.fail_files_list])+'\n')
    # 添加未匹配到压缩包的文件记录
    run_message_text.insert(tk.END, '未匹配到密码的压缩包有:\n' + '\n'.join([f'{x}' for x in obj.not_found_pwd_files])+'\n')
    # 添加整体运行情况统计结果
    run_message_text.insert(tk.END, f"""
共找到{obj.zip_file_count}个压缩包,其中{len(obj.success_files_list)}个解压成功,{len(obj.fail_files_list)}个解压失败,
{len(obj.not_found_pwd_files)}个压缩包未匹配到密码,有{len(obj.not_found_file_password)}个密码未匹配到压缩包文件。"""
)


submit_button = tk.Button(wd, text='提交运行', command=run_unzip, bg='yellow')
submit_button.grid(row=2, column=2)

# 解压缩文件的执行情况
run_message_label = tk.Label(wd, text='解压情况:')
run_message_label.grid(row=5, column=0)
# 定义密码文本的输入框,并设置所在位置,其中输入框所显示内容为tk变量password_text
run_message_text = tk.Text(wd, height=15)
run_message_text.grid(row=5, column=1, sticky=tk.E+tk.W+tk.N)

# 添加一个说明标签
info_label = tk.Label(wd, text='本小程序为学习Python程序进行开发,仅用于方便工作使用,不得用于任何违法事宜。Power By Wei Lin')
info_label.grid(row=6, column=1)

# 使窗口保持刷新
wd.mainloop()

思路解析:很基础的页面,不过记得哪个大佬说过,先实现核心的功能,其他的(美化)以后再说。此外,代码中已经把后续写的一些代码贴上了,在实际编写过程中实际上是先预留空位,后续代码实现后补充的。

  1. 有了界面,要实现功能
    3.1先实现单个文件解压缩的功能
import pathlib
import pyzipper as zp


class ExtractFile:
    def __init__(self, file_path, pwd=None, out_path=None):
        """
        初始化解压文件类的信息
        :param file_path: 需解压文件的完整路径
        :param pwd: 解压的密码,默认为None
        :param out_path: 解压出来的文件存放的路径,默认为None,即解压缩到压缩文件的相同目录下
        """

        self.file_path = file_path
        self.pwd = pwd
        # 判断一下文件是否是zip压缩包,给self.is_zip_file赋值
        if zp.is_zipfile(self.file_path):
            self.is_zip_file = True
        else:
            self.is_zip_file = False
            print(f'{self.file_path}文件并不是压缩文件')
        # 判断输出地址是否为正确路径,如正确则定义为解压缩后的输出路径,如果错误,则以压缩包所在路径为准
        if out_path is not None:
            out_path = pathlib.Path(out_path)  # 将out_path转成path对象
            if out_path.is_dir():  # 根据out_path对象的is_dir方法判断是否文件夹
                self.out_path = out_path
            else:  # 如果不是文件夹则将文件所在的路径作为输出文件夹
                self.out_path = pathlib.Path(self.file_path).parent
        else:  # 如果不是文件夹则将文件所在的路径作为输出文件夹
            self.out_path = pathlib.Path(self.file_path).parent

    def extract_all(self, pwd, out_path):
        """
        解压缩所有文件
        :return: bool
        """

        if self.is_zip_file:
            try:
                with zp.AESZipFile(self.file_path, mode='r'as zip_file:
                    zip_file.extractall(path=out_path, pwd=pwd.encode('utf-8'))
                return True
            except Exception as e:
                print(f'解压缩文件错误,错误信息为: {e}')
                return False
        else:
            print(f'{self.file_path}文件并不是压缩文件')
            return False
            
      
if __name__ == '__main__':
    file_path = 'd:/测试文件.zip'
    obj = ExtractFile(file_path)
    obj.run_extract()

思路解析:上面的代码都有注释就不一一解释了,需要提一下的是,单独建了一个py文件存放这个代码,以便调试以及后续更新功能。

3.2再实现批量解压缩文件的功能

import pathlib
import re
from extract_single_file import ExtractFile


class ExtractFiles:
 def __init__(self, root_path, password_text):
     # 需要解压缩文件所在的路径
     self.root_path = root_path
     # 初始化zip文件的个数
     self.zip_file_count = 0
     # 初始化未找到匹配密码的文件list
     self.not_found_pwd_files = []
     # 根目录中所有的zip文件字典,其中key为去除扩展名后的文件名,value为list格式,为zip文件的完整路径
     self.zip_file_dict = {}
     # 密码文本
     self.password_text = password_text
     # 初始化密码字典,其中key为短信中任务名称(与压缩包名称对应),value为set集合格式,为六位数字密码
     self.password_dict = {}
     # 初始化密码信息的个数
     self.password_count = 0
     # 初始化解压缩的dict,key为需要解压缩文件的完整路径名称,value为匹配到的密码(list格式)
     self.unzip_dict = {}
     # 初始化未找到匹配文件的密码list
     self.not_found_file_password = []
     # 初始化成功解压缩的文件list
     self.success_files_list = []
     # 初始化解压缩失败的文件list
     self.fail_files_list = []

 def get_all_zip_files(self):
     """
     为防止模块报毒,使用pathlib模块遍历根目录下的所有zip文件,生成zip_file_dict
     """

     for file in pathlib.Path(self.root_path).rglob('*.zip'):
         if not file.name.startswith('~'):
             self.zip_file_count += 1
             full_path = str(file)  # 完整路径是file对象的str格式
             filename = file.stem  # file对象的stem是去除扩展名后的文件名
             if filename in self.zip_file_dict.keys():
                 self.zip_file_dict[filename].append(full_path)
             else:
                 self.zip_file_dict[filename] = [full_path]

 def parse_password(self):
     """
     使用正则解析密码字符串,生成字典
     """

     if self.password_text is not None:
         res = re.findall(r'任务名为(.*?) 的压缩包,解压密码为(\d{6}),', self.password_text)
         if len(res) > 0:
             for key, value in res:
                 self.password_count += 1
                 if key in self.password_dict.keys():
                     self.password_dict[key].add(value)
                 else:
                     self.password_dict[key] = {value}

 def matching(self):
     """
     给压缩包与密码配对
     """

     # 创建文件字典、密码字典的副本以便后续进行修改操作
     file_dict = self.zip_file_dict.copy()
     password_dict = self.password_dict.copy()
     # 遍历匹配
     for i in range(len(file_dict)):  # 根据file_dict的长度,确定循环次数
         # 每一次从file_dict中取出一对键值对,分别为不含扩展名的文件名与文件绝对路径list
         file, full_path_list = file_dict.popitem()
         if  file in password_dict.keys():  # 如果压缩文件名在密码字典的key中
             # 取出密码的list
             pwd_list = password_dict.pop(file)
             # 将绝对路径与密码进行配对放入待解压的文件字典中
             for full_path in full_path_list:
                 self.unzip_dict[full_path] = pwd_list
         else:  # 否则将文件绝对路径放入未找到密码的文件list中
             for full_path in full_path_list:
                 self.not_found_pwd_files.append(full_path)
     if len(password_dict) > 0:  # 如果匹配结束后,密码字典中还有剩余的键值对,把它们放入未找到文件的密码list中
         for i in range(len(password_dict)):
             key, pwd_list = password_dict.popitem()
             for pwd in pwd_list:
                 self.not_found_file_password.append((key, pwd))

 def do_extract(self):
     """
     运行批量解压 
     """

     for file, pwd_list in self.unzip_dict.items():  # 遍历待解压的文件字典
         add_to_fail = True  # 将加入失败list初始化为True
         for pwd in pwd_list:  # 遍历密码list进行解压
             extract_obj = ExtractFile(file, pwd)
             res = extract_obj.extract_all(pwd=extract_obj.pwd, out_path=extract_obj.out_path)
             if res:  # 如果成功
                 self.success_files_list.append(file)
                 add_to_fail = False
                 break
         if add_to_fail:  # 如果值为True,说明所有密码均没有成功解压缩文件,因此加入有密码但解压失败的文件list中
             self.fail_files_list.append(file)

思路解析:这部分代码主要实现读取出所有zip文件,解析短信密码文本,并且进行匹配解压的过程,考虑到方便使用者,因此将文件与密码的匹配设计为多对多的方式,即目录下可能存在相同文件名的压缩包(同名文件可能在子文件夹中),密码文本可能存在重复或多条短信密码均为相同文件名的情形。
此外,解析密码文本是,需要用到正则表达式,找出文本中的文件名与密码的键值对,我使用的是“r'任务名为(.*?) 的压缩包,解压密码为(\d{6}),'”,具体情形需要具体修改。

  1. 打包成exe
    5.1 打开cmd,进入到虚拟环境的路径中:我的是"D:/work/pythonproject/venv/scripts/activate.bat"
    5.2 在cmd中,进入到存放py文件的路径,运行pyinstaller命令,我的是“pyinstaller -Fw unzip_file.py”(命令就不具体解释了,详见pyinstaller的教程)

打包结束后,目录下会出现一个dist目录,里面就是打包好的exe文件了,测试运行了一下,一切正常。

只有11M
特别说明:

如果在代码中使用os模块,则在后续打包成exe文件时,会被杀毒软件识别为病毒,所以,一开始就要避免使用os模块。(此前版本代码中使用os.walk进行文件遍历,就踩坑了,还好使用的地方不多,都改成pathlib了)


加个彩蛋

前面那些只是正常的解压缩步骤,适用的场景很小,不能体现咱的水平,咱得憋个大招:搞个暴力破解压缩包密码的功能,要是没收到密码短信或者误删短信了,还是能够解压缩文件,这才牛^_^(后来想了想,似乎这个功能也没什么软用,但就是要折腾,脑洞继续开)。

暴力破解功能实现

暴力破解只针对单个文件,那么直接在前面单个解压文件的程序中增加这个功能即可,由于密码为6位数字,一共有100万种组合,因此单线程肯定是不行的,要上多线程。此外,试验密码的顺序对于破解密码的消耗时间是有巨大影响的,因此,提供一些密码的排序方式供选择“正序、倒序、1优先、2优先等等”,以及一个“随机”方式,如果选择的方式恰好命中了正确密码的范围,那么将大大节约破解时间(有点买彩票的感觉^_^),上代码:

from extract_single_file import ExtractFile
import pyzipper as zp
import queue
import threading
import time
from itertools import product
from random import shuffle

comm = False  # 定义一个全局变量信号
pwd_queue = queue.Queue()  # 定义一个存放待测试密码的queue,用于多线程通信
fail_queue = queue.Queue()  # 定义一个存放失败密码的queue
method_dict = {
    '1优先'1,
    '2优先'2,
    '3优先'3,
    '4优先'4,
    '5优先'5,
    '6优先'6,
    '7优先'7,
    '8优先'8,
}  # 定义优先级数字字典,0和9分别是正序和倒序,无需特别定义


class CrackExtract(ExtractFile):
    def __init__(self, file_path, pwd_length=6, method=None, pwd=None, out_path=None):
        # 继承父类属性
        super(CrackExtract, self).__init__(file_path, pwd, out_path)
        # 初始化密码长度
        self.pwd_length = int(pwd_length)
        # 初始化暴力破解的顺序
        self.method = method
        # 初始化打开zip文件,后续需要关闭
        self.zip_file = zp.AESZipFile(self.file_path, mode='r')
        # 初始化尝试次数
        self.try_count = 0

    def product_pwd_queue(self):
        """
        创建存放待破解密码的queue
        """

        global comm, pwd_queue  # 声明全局变量
        num_list = list(range(10))
        if self.method == '逆序':  # 如果是逆序方式,则倒转num_list
            num_list = num_list[::-1]
        elif self.method in method_dict.keys():  # 如果数字优先,则重新组合num_list,将优先数字向两测重新排序
            k = method_dict[self.method] + 1
            part1 = num_list[:k]
            part2 = num_list[k:]
            num_list = []
            while part1 or part2:
                if part1:
                    num_list.append(part1.pop())
                if part2:
                    num_list.append(part2.pop(0))
        # 使用itertools的product方法创建6位密码的生成器,拼接后放入pwd_queue中
        if self.method == '随机':  # 使用random模块的shuffle随机打散num_list
            pwd_list = [x for x in product(num_list, repeat=self.pwd_length)]
            shuffle(pwd_list)
            for s in pwd_list:
                if comm:
                    return
                pwd_queue.put(''.join([str(x) for x in s]))
        else:
            for s in product(num_list, repeat=self.pwd_length):
                if comm:  # 如果信号已经转为True,无需继续生产密码
                    return
                pwd_queue.put(''.join([str(x) for x in s]))

    def crack_extract(self):
        """
        尝试解压缩程序
        """

        # 声明全局变量
        global comm, pwd_queue, fail_queue
        while True:  # 开启循环
            if not pwd_queue.empty():  # pwd_queue不为空时
                pwd = pwd_queue.get()  # 取出一个密码尝试解压缩是否成功
                try:
                    self.zip_file.extractall(path=self.out_path, pwd=pwd.encode('utf-8'))
                    pwd_queue.queue.clear()  # 若成功清除pwd_queue剩余密码
                    comm = True  # 若成功,修改信号为True
                    self.pwd = pwd.encode('utf-8')
                    print(f'解压缩成功,密码是{pwd}')
                except (TypeError, RuntimeError):
                    self.try_count += 1
                    fail_queue.put(pwd)  # 若失败,将失败密码存入失败队列
                    print(f'正在解压,尝试密码串{pwd}失败,还剩余{pwd_queue.qsize()}个密码串待试验')
                pwd_queue.task_done()  # 处理完成
            elif comm:  # 若信号为True,终止循环
                break
            else:  # 若pwd_queue为空,等待0.2秒
                time.sleep(0.2)

    def run_extract(self):
        """
        运行解压程序
        """

        # 声明全局变量
        global comm, pwd_queue, fail_queue
        comm = False  # 将信号初始化为False
        # 初始化多线程list,并添加一个声明密码queue的线程
        threadlist = [threading.Thread(target=self.product_pwd_queue, name='create')]
        # 添加10个破解线程
        for x in range(10):
            th = threading.Thread(target=self.crack_extract, name=f'extract{x}')
            threadlist.append(th)
        start = time.time()  # 开始时间
        for t in threadlist:  # 开启线程
            t.start()
        for t in threadlist:  # 等待线程结束
            t.join()
        end = time.time()  # 结束时间
        cost_time = round(end - start, 4 )  # 所用时长(秒)
        self.zip_file.close()  # 关闭zip文件
        print(f'解压成功,总用时{cost_time}秒')
        return self.pwd, self.try_count, cost_time


if __name__ == '__main__':
    file = r'D:\test\upzip\测试文件.zip'
    obj = CrackExtract(file, method='3优先')
    obj.run_extract()
暴力破解测试截图
破解功能的界面

由于不想直接体现在程序界面中,因此,破解功能的界面写了一个新的交互界面,代码如下:

import tkinter as tk
from tkinter import filedialog, messagebox
from crack_extract import CrackExtract

RADIO_DICT = {
    0'正序',
    9'倒序',
    1'1优先',
    2'2优先',
    3'3优先',
    4'4优先',
    5'5优先',
    6'6优先',
    7'7优先',
    8'8优先',
    10'随机'
}


class PowerExtractWindow:
    def __init__(self):
        self.wd = tk.Toplevel()
        self.wd.title('破解密码小程序V1.0')
        self.wd.geometry('600x200')
        self.file_path = tk.StringVar()
        self.path_button = None
        self.path_entry = None
        self.submit_button = None
        self.mes_window = None
        self.radio = tk.IntVar()

    def choose_file(self):
        """
        设置选择解压缩文件包所在路径的按钮及功能方法
        """

        self.file_path.set(filedialog.askopenfilename(
            title='请选择文件',
            initialdir='/',
            filetypes=[('压缩文件''*.zip')]
        ))

    def power_extract(self):
        """
        开启破解的方法
        """

        # 由于破解耗时较长,弹出一个窗口让用户再次确认是否开始
        answer = messagebox.askokcancel('确认是否开始''破解密码需要等待较长时间,你确定更要开始吗?')
        if answer:  # 确认开始
            self.mes_window.delete(1.0, tk.END)  # 清理信息窗口的内容
            # 初始化破解的对象
            crack_obj = CrackExtract(self.path_entry.get(), method=RADIO_DICT.get(self.radio.get()))
            # 执行破解程序,并获得正确破解后的密码、尝试次数、用时等信息,并输出到窗口上
            pwd, try_count, cost_time = crack_obj.run_extract()
            mes_text = f'解压文件{self.path_entry.get()}成功,正确密码是{pwd.decode("utf-8")},' \
                       f'共尝试了{try_count}次,总耗时{int(cost_time // 60)}{cost_time % 60}秒'
            self.mes_window.insert(1.0, mes_text)

    def layout(self):
        """
        对窗口进行布局的方法
        """

        # 定义压缩包路径的选择按钮,并设置所在位置,其中按钮点击的命令为get_unzip_files_path
        self.path_button = tk.Button(self.wd, text='请选择破解文件', command=self.choose_file)
        self.path_button.grid(row=0, column=0)
        # 定义压缩包路径的输入框,并设置所在位置,其中输入框所显示内容为tk变量unzip_files_path
        self.path_entry = tk.Entry(self.wd, textvariable=self.file_path, width=60)
        self.path_entry.grid(row=0, column=1, columnspan=10)
        # 定义压缩包路径的输入框,并设置所在位置,其中输入框所显示内容为tk变量unzip_files_path
        self.submit_button = tk.Button(self.wd, text='开始破解', command=self.power_extract, bg='red')
        self.submit_button.grid(row=5, column=0)
        
        # 定义选择破解密码的排序方式,单选项,并布局
        r_label = tk.Label(self.wd, text='请选择破解的密码排序方式:')
        r_label.grid(row=1, column=0, rowspan=3)
        col = 0
        for k, v in RADIO_DICT.items():
            exec(f'tk.Radiobutton(self.wd, text="{v}", variable=self.radio, value={k}).grid(row={col//5+1}, column={col%5+1})')
            col += 1

        # 定义运行消息窗口
        self.mes_window = tk.Text(self.wd, height=5, width=60)
        self.mes_window.grid(row=5, column=1, columnspan=10)

        self.wd.mainloop()


def open_power_window():
    """
    打开破解的窗口函数
    """

    new_wd = PowerExtractWindow()
    new_wd.layout()


if __name__ == '__main__':
    wd = tk.Tk()
    wd.title('暴力破解testV1.0')
    wd.geometry('400x200')
    submit_button = tk.Button(wd, text='打开二级窗口', command=open_power_window, bg='red')
    submit_button.pack()
    wd.mainloop()
破解窗口的测试截图

将破解功能加入原界面中(隐藏界面)

给压缩包加密码本身是为了数据保密,而暴力破解密码,某种角度看,似乎有点不合适,因此,直接放在界面中不太合适,咱搞个隐藏界面,必须输入密码口令才能打开,至于口令就用“上上下下左右左右BABA”(致敬一下经典,嘿嘿)。

以下代码在原交互界面上增加
# 引入新的破解界面
from power_unzip import open_power_window  

def judge(func):
    """
    装饰器函数,用于判断是否为特殊口令打开隐藏界面,
    :param func: 需要增加功能的函数
    """

    def open_power_wd():
        # 获取密码文本的输入框的输入内容,如何符合条件,则运行破解程序
        password_text = password_text_text.get(1.0'end')
        if password_text.strip() == '上上下下左右左右BABA'
            open_power_window()
        return func()

    return open_power_wd
将装饰器放置在需要装饰的函数前

完成上述步骤后,再次使用pyinstaller进行打包即可。

成品展示
破解测试
破解程序的测试结果

最终总结

之所以开这么一个脑洞,其实主要是设计了一个场景,为了锻炼一下综合的应用能力,把学到的分项知识进行一次融合。

整个过程中用到的模块有:

  1. pyinstaller,打包exe
  2. tkinter,交互界面
  3. pathlib,路径与文件
  4. theater,多线程
  5. queue,多线程通信
  6. itertools.product,求多个可迭代对象的笛卡尔积
  7. random.shuffle,随机打散

在实现过程中,按自己理解进行了分项的拆解实现,以便后续进行功能的迭代;同时,应用了装饰器,在不改变原代码的情况下,增加功能等等。通过这样的过程,加深对各个功能的理解。

好吧,这次的脑洞先开到这里了,等有时间了咱继续开脑洞。


最后,推荐蚂蚁老师的《Python零基础入门到数据分析到办公自动化实战》课程,购买后加老师微信答疑:ant_learn_python




Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/123714