· 背景和需求

因为疫情期间嘛,老爹也只能开网课,线上教棋了,但是网课又不开摄像头的那种,根本不知道学生在干嘛,这不就有了一个学生在那表面上着网课实际上是在那玩游戏,被他妈妈逮了个正着…因此我老爹就想看看能不能上网课的时候让他只能用上网课的那个程序,而正好我在看python的psutil的模块,就尝试着帮我老爹写一个看看喽

· 分析

1. 首先我需要检测正在运行进程,之后找到在封禁名单内的主进程,之后shutdown就可,这部分psutil模块就可以实现
  2. 作为一个程序,我还是得写一个ui界面的,本来是想用tkinter的,不过Python这个标准GUI库功能确实不咋地,这里就现学了一下wxpython来作为程序的ui界面
  3. ui界面这里主要是要提供一个最小化到托盘以及推出功能,不然的话现在的这些家长不太知道怎么退出就比较头疼了

· 代码实现

1. 主逻辑部分

· 这里我们把主逻辑部分写到一个线程里,为此我们需要线程模块,这里从threading模块中导入Thread类,之后定义我们自己的线程类,继承自Thread,主逻辑放到重写的run()方法
  · 正式开始主逻辑部分,这里需要被限制程序的主进程名,为了以后好扩展,这里我们将这些主进程名放到一个列表里,之后通过转换为json格式存储到文件中,为此我写了一个config.py用来实现该功能

import json# 存储限制进程列表到文件中去
def main():try:f = open('learn_tool.conf', 'w', encoding='utf-8')limit_process_list = ['DouyuLive.exe', 'QQGame.exe', 'MicrosoftEdge.exe', '360se.exe', '360chrome.exe','firefox.exe', 'chrome.exe', 'QQBrowser.exe', 'SogouExplorer.exe']json_list = json.dumps(limit_process_list)f.write(json_list)except LookupError:print('指定了未知编码!')except IOError as ex:print(ex)print('写文件时发生错误!')finally:f.close()print('操作成功!')if __name__ == "__main__":main()

· 运行config.py就会生成存放限制进程名的配置文件:learn_tool.conf,之后也可以直接去这个文件中增添其他要限制的进程(ps:本来是应该在ui界面里加入这个增添限制进程功能的,有点懒,先放着吧)

· 之后在类中写一个前面的run()方法中打开该文件,将其从json格式转为list即可;关键在之后:这里直接设置死循环,因为要不断的检测是否有被限制进程,使用psutil.pids()获取所有当前正在运行的进程id的列表,之后for循环遍历,通过psutil.Process(pid).name()来__获取该pid对应的进程名__,之后判断进程名是否在限制进程的list中即可:不在,则继续循环;在,则调用terminate()方法来__关闭进程__

# 自定义限制进程
class AntiInsertion(Thread):def run(self):# 获取要限制的进程列表limit_process_list = self.read_conf('learn_tool.conf')while True:# 存放正在运行的限制进程的信息now_run_limit_process_list = []# 获取当前正在运行的所有进程的pidtry:now_pids = psutil.pids()       # 当前所有进程pid的listfor pid in now_pids:if pid in psutil.pids():_p = psutil.Process(pid)    # 获取每个进程if _p.name() in limit_process_list:now_run_limit_process_list.append(_p)for i in now_run_limit_process_list:if i.pid in psutil.pids():log.my_log(1, str(i.pid) + ":" + i.name())i.terminate()else:log.my_log(2, i.name() + " not exist")except Exception as error:log.my_log(2, error)# 读取配置文件信息def read_conf(self, filename) -> list:try:conf_f = open(filename, 'r', encoding='utf-8')limit_process_list = json.loads(conf_f.read())except FileNotFoundError:print('系统配置文件未找到!')except LookupError:print('指定了未知编码!')except UnicodeDecodeError:print('读取文件时解码错误!')return limit_process_list

· 上面代码中的log为我__自定义的日志记录模块__:log.py,用来将每次_关闭进程的信息_及_错误信息_存入到log.txt文件中

import loggingdef my_log(model: int, message: str):# 设置logging模式logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', filename='./log/log.txt', filemode='a')logger = logging.getLogger(__name__)if model == 1:logger.info(message)elif model == 2:logger.warning(message)if __name__ == '__main__':# 测试数据my_log(1, '1111')my_log(2, '2222')

2· ui部分设计

· 这里选择了__wxpython__来进行ui设计,需要定义一个自己的__Frame类__,从wxpython继承,在__init__()中初始化窗口大小、窗口位置、ui背景颜色、托盘以及各种控件等,不过这里我们并不需要什么控件,只需要实现__托盘__和__右击托盘退出__功能

import wx
import sys
import win32apiclass MyFrame(wx.Frame):# 程序主窗体类,从wx.Frame继承def __init__(self):wx.Frame.__init__(self, None, -1, APP_TITLE, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)# 给Frame增添托盘,定义在下面self.taskBarIcon = MyTaskBarIcon(self)self.SetBackgroundColour(wx.Colour(224, 224, 224))self.SetSize((400, 400))self.Center()# 下面代码用于处理图标if hasattr(sys, 'frozen') and getattr(sys, 'frozen') == "windows_exe":exe_name = win32api.GetModuleFileName(win32api.GetModuleHandle(None))icon = wx.Icon(exe_name, wx.BITMAP_TYPE_ICO)else:icon = wx.Icon(APP_ICON, wx.BITMAP_TYPE_ICO)self.SetIcon(icon)# 给gui窗体上的关闭按钮绑定隐藏到托盘事件self.Bind(wx.EVT_CLOSE, self.OnHide)# 如果需要添加扩展控件,写在__init__()中即可pass# 定义函数用于隐藏程序到托盘def OnHide(self, event):self.Hide()

· 之后我们来实现ui界面的关键:托盘的实现,这里要用到wx.adv,依旧定义我们自己的托盘类,继承自wx.adv.TaskBarIcon;在__init__()中__初始化Frame、图标设置等__,创建菜单需要重写CreatePopupMenu()方法,在该方法中我们需要使用wx.Menu()来__创建菜单__,之后通过wx.Menu.Append()方法__将菜单项添加到菜单中__,这里每个菜单项需要用wx.MenuItem()来创建,而__每个菜单项的点击事件的绑定__则使用Bind()来完成,完成之后return menu

# 托盘类
class MyTaskBarIcon(wx.adv.TaskBarIcon):def __init__(self, frame):wx.adv.TaskBarIcon.__init__(self)self.Frame = frameself.SetIcon(wx.Icon(APP_ICON), APP_TITLE)# 获取Menu数据def set_menuitem_data(self):data_list = (('About', self.on_about), ('Show', self.on_show), ('Close', self.on_close))return data_list# 创建菜单def CreatePopupMenu(self):my_menu = wx.Menu()for itemName, itemHolder in self.set_menuitem_data():if not itemName:my_menu.AppendSeparator()continue# 创建每一个菜单项menu_item = wx.MenuItem(None, wx.ID_ANY, text=itemName, kind=wx.ITEM_NORMAL)my_menu.Append(menu_item)self.Bind(wx.EVT_MENU, itemHolder, menu_item)return my_menu# 显示app相关信息,这里加上作者信息吧还是,2333def on_about(self, event):wx.MessageBox('signed by sophistic-cat', '关于')# 显示主菜单def on_show(self, event):'''# 这里本来设计是用来显示主窗体的,但为了避免小孩子们通过任务管理器关闭,就把这里注释掉了if self.Frame.IsIconized():self.Frame.Iconize(False)if not self.Frame.IsShown():self.Frame.Show(True)self.Frame.Raise()self.Frame.Maximize(True)   # 最大化显示'''pass# 退出appdef on_close(self, event):# 实例化了一个自定义的弹窗类myED = ExitDialog()# 显示弹窗myED.ShowModal()# 判断密码是否正确,正确则退出# 这里是类中有一个flag标志位,当密码正确时会将flag设置为true,通过get_flag()返回if(myED.get_flag()):wx.Exit()

· 之后我们来定义上面的__退出弹窗__,依旧写一个自己的__弹窗类__,继承自wx.Dialog,和wx.Frame类似,在__init__()中进行初始化、拜访控件位置、设置弹窗大小位置等,这里主要是要实现给Button绑定事件和提取TextCtrl中的内容;__绑定事件__很简单,依旧是用Bind;而__提取TextCtrl中的输入内容__也有现成的方法,调用TextCtrl的GetValue()方法即可。对了,这里我们将退出密码依旧以文件形式保存,然后本来想做个加密算法的,不过,emmmm,懒嘛,就先明文保存到文件吧,哎嘿嘿

# 定义退出时输入密码的Dialog
class ExitDialog(wx.Dialog):def __init__(self):wx.Dialog.__init__(self, None, -1, "Exit_verify", size=(300, 100))# 设置静态文字,提示后面输入密码self.static_text = wx.StaticText(self, -1, u'请输入密码:', pos=(10, 20), size=(80, -1), style=wx.ALIGN_RIGHT)# 设置输入框self.Exit_Pwd = wx.TextCtrl(self, -1, '', pos=(90, 15), size=(100, -1), style=wx.TE_PASSWORD)# 设置退出按钮self.Sure_Bt = wx.Button(self, -1, '确认', pos=(200, 12), size=(50, -1))self.flag = Falseself.Center()# 给按钮绑定“检查密码”点击事件self.Sure_Bt.Bind(wx.EVT_BUTTON, self.checked_pwd)def checked_pwd(self, evt):# 获取输入框的文字content = self.Exit_Pwd.GetValue()# 打开密码文件,判断是否相同with open("./data/pwd.txt", "r") as f:date = f.read()if content == date:# 密码一致,将标志位flag设置为Trueself.flag = Trueself.Destroy()else:# 密码不一致,弹出密码错误的提示框wx.MessageBox('密码错误!', 'Error')# 用于外部获取flag值,来判断密码输入是否正确def get_flag(self):return self.flag

· 至此基本功能、ui设计完毕,不过为了再玩一下wxpython,就又添加了一个__启动界面__,我们这里新建一个函数用来创建启动界面,两行代码就可实现,关键在于wx.adv.SplashScreen()的使用

def create_splash():# 创建开始界面screen = wx.Image(r'./pic/welcome.jpg').ConvertToBitmap()   # 选择一张图片(bitmap格式)来做启动界面'''这里注意下参数含义:第一个参数是bitmap图;第二个参数是格式,这里设置为居中在屏幕中间并停顿一段时间;第三个参数是设置停顿时间,2000即为2s第四个参数是parent,这里没有,设置为None即可'''wx.adv.SplashScreen(screen, wx.adv.SPLASH_CENTRE_ON_SCREEN | wx.adv.SPLASH_TIMEOUT, 2000, None, -1)

· 之后我们要新建自己的__主程序类__,继承自wx.App,在这里重写OnInit()方法(这是主程序入口类),将其Frame设置为我们的Frame实例即可

class MainApp(wx.App):Frame = None# 主程序入口类def OnInit(self):self.SetAppName(APP_TITLE)self.Frame = MyFrame()# self.Frame.Show()     # 设置启动时显示主窗体return True

· 最后,创建我们主程序实例,启动我们的__主逻辑进程__并设置为__守护进程__(这样的话,当我们退出时就会关闭该进程),启动开始界面,mainloop我们的主程序

if __name__ == "__main__":app = MainApp(redirect=True, filename="./log/log_debug.txt")AntiInsertion(daemon=True).start()create_splash()app.MainLoop()

3. 代码打包问题

· 这里__打包__使用的是__pyinstall__,我的整个程序目录如下,打包则在main.py文件所在位置打开cmd进行打包,打包代码如下:
    参数说明:-D除了主程序外还会在dist文件夹下生成很多依赖文件
         -i选择.exe的图标文件
         -noconsole去除cmd黑框
  
  打包命令pyinstall -D main.py -i ./pic/app_icon.ico -noconsole
  
  · 生成的程序在dist目录下;但是有__一个大问题__:程序所需的/data、/log、/pic等文件都没有打包进去,emmm,所以直接运行会报错,当你把main.exe依赖的文件复制进去之后就ok了

程序演示

emmm,整的gif有点大~感兴趣的可以私聊啊,虽然没什么难的

使用Python实现伪防沉迷工具相关推荐

  1. 基于AI伪原创API的python伪原创工具开发

    功能上分别具有4种ai智能算法,在线伪原创,批量伪原创,自定义文本替换等功能,自定义锁词,在线API功能.可以对接采集工具和个人网站使用.智能改写后的文章具有可读性高,原创度高的特点,对各大搜索引擎都 ...

  2. python伪原创工具开发_在线伪原创工具www.bolewei.com的开发过程

    中文伪原创工具需要考虑的问题 我开始思考,目前已有的中文伪原创工具,效果差在哪些地方呢?我想到以下几个: 一.分词问题. 中文和英文不同,无论是搜索引擎的蜘蛛,还是其他自然语言处理的语料分析,都是需要 ...

  3. python伪原创工具开发_现在有哪些好用的伪原创工具?

    有些自媒体人或者博主可能经常苦于写不出原创稿子而大把的掉头发吧(程序员也掉!),最近是不是毕业崽们被论文折磨的痛不欲生?说白了就是为了原创,就是为了降重,那么今天这篇你不能错过!好几个软件(网站),贝 ...

  4. python文章伪原创_对国内首款伪原创工具作者泊君的访谈

    提及SEO伪原创工具,想必大家都非常的熟悉!但是当谈及到SEO伪原创工具的鼻祖,估计很多人都非常的陌生,因为他在SEO行业非常的低调,很少在SEO界露面及参加各种SEO峰会:他的学生都是SEO行业中的 ...

  5. Python程序伪编译与打包

    众所周知,Python是纯粹的自由软件,源代码和解释器CPython遵循GPL(GNU General Public License)协议.那么很自然会有人有这样的疑问:难道Python程序只能以源代 ...

  6. 太强了,Python 开发桌面小工具,让代码替我们干重复的工作~

    作者 | Cherish 来源 | 杰哥的IT之旅 决定写这篇文章的初衷是来源于一位小伙伴的问题,关于"如何根据数据源用 Python 自动生成透视表",这个问题背后有个非常好的解 ...

  7. arcgis里python窗口运行,在 Python 窗口中执行工具

    当第一次打开 Python 窗口时,它会显示类似这样的界面: 左侧区域为 Python 的主提示窗口,在这里执行 Python 命令.右侧区域为帮助和语法窗口,工具运行时,在这里显示执行消息:输入代码 ...

  8. python编写测试工具-python 写一个性能测试工具(一)

    国庆重新学习了一下go的gin高性能测试框架. 用JMeter来测试gin与flask接口的性能,差别很大. 为什么我自己不尝试写一个性能工具,性能工具的核心就是 并发 和 请求. 请求可以选择Pyt ...

  9. python代码安全扫描工具

    python代码安全扫描工具:Coverity. Fortify.SecMissile(漏扫,对源代码提供基于语义的搜索和分析能力,实现已知安全漏洞的快速扫描) 转载于:https://www.cnb ...

最新文章

  1. 第二课 , 启动 ./start-all.sh
  2. Js文本溢出自动添加省略号ellipsis
  3. 汇编语言---统计数据区的正、负数并分开存放
  4. 系统什么时候会用到swap分区?
  5. python基于dict、defaultdict、Counter的累加器
  6. 硬盘与电线挨着会高温吗_机械硬盘时代徐徐落幕?出货量再减50万件,你还会买新机械盘吗?...
  7. GroovyHelp方便查看java api
  8. Nginx for Zabbix 3.2官方监控模板
  9. linux启用dcb步骤,Linux DCB体系——简短概述
  10. 第十九章 TCP的交互数据流
  11. linux远程连接命令有哪些,linux系统远程连接命令有哪些
  12. 证书更新提示,网易漫画等...
  13. 经典详细的Struts2教程(附案例源码)
  14. php 中%3cspan%3e,vue实战(4)——网站统计之——友盟百度统计
  15. php symlink,php函数symlink详解
  16. ceph存储 ceph集群Paxos算法实现
  17. 国徽FLASH SM25QH256M烧录问题总结
  18. 什么是 IT 基础架构管理
  19. 若依前后端分离框架验证码的学习
  20. 北京理工大学·Python网络爬虫与信息提取·知识整理

热门文章

  1. patch文件的生成和使用
  2. # 云计算建筑技术实践
  3. 中国电信在计算机网络扮演的角色,计算机网络.ppt
  4. 文本相似性计算--MinHash和LSH算法
  5. TcaplusDB君 · 行业新闻汇编(8月9日)
  6. html计算数学表达式,如何使用MathCalc在JavaScript中实现基本的数学表达式计算器...
  7. c标签escapeXml
  8. linux 服务器ip修改
  9. android显示动画一直播放器,酷炫的Android交互动画和视觉效果:高仿音悦台播放页面...
  10. BloomFilter 布隆过滤器