效果图:
主要使用了pyautogui和pyperclip两个第三方库实现,如多使用了图像匹配功能会使pyautogui引入了Pillow等库,如果代码涉及到了关键参数还需要OpenCV库等等。
特意写了很多注释,供学习使用。
完整代码:
import os
import threading
import time
from tkinter import Tk, StringVar, Entry, Label, Button, DISABLED
import pyautogui
import pyperclip
def read(file):
f = open(file, 'r')
str_list = f.read().split('\n')
return str_list
def input_pw(password): # 输入密码
pyautogui.keyDown('backspace')
time.sleep(2)
pyautogui.keyUp('backspace')
pyautogui.write(password, interval=0.1)
def login(qq_msg, qq_path):
# 获取登录qq账号密码
qq_msg = qq_msg.split('#')
qq = qq_msg[0]
password = qq_msg[1]
# 打开QQ
os.startfile(qq_path)
time.sleep(8)
# 获取运行时的屏幕分辨率(因为我的指定坐标是基于1920*1080的,要适应不同分辨率变化)
width, height = pyautogui.size().width, pyautogui.size().height
# 输入账号
pyautogui.click(int(1060*width/1920), int(560*height/1080)) # 点击账号输入框
pyperclip.copy(qq)
pyautogui.hotkey('ctrl', 'v')
time.sleep(0.5)
# 输入密码
pyautogui.click(int(1060*width/1920), int(610*height/1080)) # 点击密码输入框
input_pw(password)
time.sleep(0.5)
pyautogui.press('enter')
class QqOnHook:
def __init__(self):
"""初始化一个界面"""
self.window = Tk()
self.window.title('QQ挂机')
window_width, window_height = 500, 250
screenwidth, screenheight = pyautogui.size().width, pyautogui.size().height
# 设置窗口居中显示
self.window.geometry("%dx%d+%d+%d" % ( # 前两个参数是窗口的大小,后面两个参数是窗口的位置
window_width, window_height, (screenwidth - window_width) / 2, (screenheight - window_height) / 2))
self.window.resizable(False, False) # 规定窗口不可缩放
self.day_num = 0
self.txt1 = StringVar()
self.statr_time = StringVar()
onhook_time = StringVar()
onhook_time.set("125")
entry1 = Entry(self.window, width=30, textvariable=self.txt1,
state="readonly", font=('宋体', 20), fg='blue', justify='center')
entry2 = Entry(self.window, width=34, textvariable=self.statr_time,
state="readonly", font=('宋体', 18))
label1 = Label(self.window, text="每日启动时间: ", font=('宋体', 15))
label2 = Label(self.window, text="时", font=('宋体', 15))
label3 = Label(self.window, text="分", font=('宋体', 15))
self.entry3 = Entry(self.window, width=4, font=('宋体', 20))
self.entry4 = Entry(self.window, width=4, font=('宋体', 20))
label4 = Label(self.window, text="单Q挂机时长: ", font=('宋体', 15))
self.entry5 = Entry(self.window, width=4, textvariable=onhook_time, font=('宋体', 20))
label5 = Label(self.window, text="分", font=('宋体', 15))
self.button = Button(self.window, width=9, height=2, text='开始', font=('黑体', 20), command=self.run)
# 设置界面布局
entry1.grid(row=0, column=0, columnspan=6)
entry2.grid(row=1, column=0, columnspan=6)
label1.grid(row=3, column=0, columnspan=2)
self.entry3.grid(row=3, column=2)
label2.grid(row=3, column=3)
self.entry4.grid(row=3, column=4)
label3.grid(row=3, column=5)
label4.grid(row=4, column=0, columnspan=2)
self.entry5.grid(row=4, column=2)
label5.grid(row=4, column=3)
self.button.grid(row=5, column=2, rowspan=2, columnspan=2)
self.window.mainloop()
def run(self): # 启动一个线程执行挂机任务
hour = self.entry3.get() # 获取每日启动时间
minute = self.entry4.get()
run_time = self.entry5.get() # 获取单Q挂机时间
if hour.isdigit() and 0 <= int(hour) <= 24 and minute.isdigit() and 0 <= int(minute) < 60 \
and run_time.isdigit() and int(run_time) > 0: # 输入检测
self.readonly_state()
t = threading.Thread(target=self.count_down, args=(int(hour), int(minute), int(run_time),))
t.setDaemon(True) # 守护线程,退出界面后回收线程
t.start()
def count_down(self, hour, minute, run_time): # 定时函数
still_time = 0
while True:
t = time.localtime()
last_hour = hour - 1 # 指定小时的上一个小时
if hour == 0: # 排除特殊的小时
last_hour = 23
if t.tm_hour == last_hour or (t.tm_hour == hour and t.tm_min < minute): # 逼近 指定小时
# 计算离 指定时间 还有多久
if t.tm_hour == last_hour:
still_time = (59 - t.tm_min) * 60 + (59 - t.tm_sec) + minute * 60
elif t.tm_hour == hour:
still_time = (minute - 1 - t.tm_min) * 60 + (59 - t.tm_sec)
time.sleep(still_time)
self.start(run_time)
else:
time.sleep(3000) # 每50分钟判断一次当前小时
def start(self, n): # 启动QQ并定时关闭
self.window.after(0, self.update)
content = read('登录qq.txt')
qq_path = content[0] # 获取qq路径
login_qq_list = content[1:] # 获取登录qq
for login_qq in login_qq_list:
if login_qq: # 避免空值
login(login_qq, qq_path)
time.sleep(n * 60) # 单Q运行时间
os.system("taskkill /F /IM QQ.exe") # 关闭QQ
time.sleep(5)
def update(self): # 记录挂机行为
self.day_num += 1
self.txt1.set("已挂机 " + str(self.day_num) + " 天")
self.statr_time.set("上次启动时间:" + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
def readonly_state(self):
self.txt1.set("关闭软件可取消")
self.button["text"] = "挂机中"
self.button['state'] = DISABLED
self.entry3.configure(state="readonly")
self.entry4.configure(state="readonly")
self.entry5.configure(state="readonly")
if __name__ == '__main__':
QqOnHook()
然后在同一目录下创建一个登录qq.txt文件,并在首行填写QQ路径,后面的行填写账号密码,账号密码以“#”号分隔,登录qq.txt文件格式如下:
最后附上打包好的exe文件,下载即可直接使用【求赞!】
放在服务器持久运行需要保持鼠标、键盘、剪切板正常运行,所以要配合我写的另一个软件使用: