如何停止Python中运行的线程并重新启动?
解决WhatsApp机器人重复解除静音问题
问题背景
开发基于pyautogui的WhatsApp趣味机器人,未使用Selenium(规避WhatsApp频繁代码变更带来的重复开发)。执行!mute命令时会启动unmute线程,定时为用户解除静音;但执行!unmute命令时,若原unmute线程仍在运行,会导致重复解除静音的问题,需要实现终止当前运行线程后再启动新的unmute线程。
解决方案
核心是利用Event对象实现线程的优雅终止,同时维护全局线程引用,在启动新线程前先终止旧线程。
修改要点
- 重构
unmute函数,将一次性休眠改为循环检查终止信号,确保线程能及时响应终止指令 - 新增全局变量存储当前运行的unmute线程,方便后续追踪和控制
- 在
!mute和!unmute命令的处理逻辑中,先触发终止信号、等待旧线程结束,再启动新线程
修改后的完整代码
from pyautogui import moveTo, click, rightClick, write, keyDown, keyUp, hotkey, scroll import pyautogui import pyperclip import re import time from threading import Thread, Event import sys unmutestoploop = Event() current_unmute_thread = None # 全局变量存储当前unmute线程 def send(message1): pyautogui.moveTo(189, 20, 0.1) pyautogui.click() pyautogui.moveTo(1000, 960) pyautogui.click() mes = re.sub('OpenAI', 'BainBan(Ben)', message1) mes2 = re.sub('ChatGPT', "Makise Kurisu (MK)", mes) pyperclip.copy(mes2) pyautogui.hotkey("ctrl", "v") pyautogui.keyDown("ENTER") pyautogui.keyUp("ENTER") def checkuserperms(): time.sleep(0.2) pyautogui.moveTo(650, 850) time.sleep(0.2) pyautogui.click() pyautogui.moveTo(1550, 580) time.sleep(1) pyautogui.dragTo(1700, 580, 1) time.sleep(0.2) pyautogui.hotkey("ctrl", "c") time.sleep(0.2) moveTo(1370, 190) time.sleep(0.2) pyautogui.click() copy = pyperclip.paste() print(copy) if copy == "40 746 499 232" or copy == "40 740 981 295": return "yes" elif "40" not in pyperclip.paste(): send("A aparut o eroare in a iti verifica permisiunile, incearca din nou acum xx") return "no" def unmute(time34=1, name1="test"): send(f"{name1} isi va lua unmute in {time34}s") global unmutestoploop # 循环检查终止信号,替代一次性sleep remaining_time = time34 while remaining_time > 0 and not unmutestoploop.is_set(): time.sleep(1) remaining_time -= 1 if unmutestoploop.is_set(): # 线程被终止,直接退出 unmutestoploop.clear() return # 执行解除静音操作 moveTo(1000, 200) time.sleep(0.5) click() time.sleep(0.5) moveTo(1800, 400) scroll(-600) time.sleep(0.5) moveTo(1850, 1000) click() time.sleep(0.5) moveTo(1000, 300) click() time.sleep(1) pyautogui.write(f"{name1}") time.sleep(1) moveTo(1000, 350) time.sleep(0.5) click() time.sleep(0.5) moveTo(1100, 380) time.sleep(0.5) click() time.sleep(2) moveTo(740, 220) time.sleep(0.5) click() time.sleep(0.5) moveTo(1370, 190) time.sleep(0.5) click() send(f"{name1} si-a luat unmute") def mute(name, time2, reason="None"): global current_unmute_thread if name == "Beni" or name == "B" or name == "Ben" or name == "Beni Noul" or name == "Marius" or name == "Mari" or name == "M" or name == 'Ma' or name == "Mar" or name == "Mariu": send("Scuze, n-ai permisiune pentru a face asta xx") return else: pyautogui.moveTo(689, 877, 0.1) pyautogui.moveTo(820, 877, 0.1) pyautogui.click() time.sleep(0.2) pyautogui.moveTo(675, 820, 0.1) moveTo(1000, 200) time.sleep(1) click() moveTo(1800, 400) time.sleep(1) scroll(-600) moveTo(1850, 1000) time.sleep(1) click() time.sleep(0.2) moveTo(1000, 300) click() time.sleep(1) pyautogui.write(f"{name}") time.sleep(1) moveTo(1000, 350) time.sleep(0.2) click() time.sleep(0.2) moveTo(1100, 450) time.sleep(0.2) click() time.sleep(2) moveTo(740, 220) time.sleep(0.2) click() time.sleep(0.2) moveTo(1370, 190) time.sleep(0.2) click() send(f"{name} si-a luat mute pentru {time2}s motiv: {reason}") # 启动新线程前先终止旧线程 if current_unmute_thread and current_unmute_thread.is_alive(): unmutestoploop.set() current_unmute_thread.join() current_unmute_thread = Thread(target=unmute, args=(int(time2), name)) current_unmute_thread.start() def ask(what): logo = pyautogui.locateOnScreen('2.png') print("start") time.sleep(3) pyautogui.moveTo(500, 10) pyautogui.click() moveTo(100, 170) click() pyautogui.moveTo(1000, 930) pyautogui.click() pyperclip.copy(what) pyautogui.hotkey("ctrl", "v") pyautogui.keyDown("ENTER") pyautogui.keyUp("ENTER") time.sleep(10) try: x = logo.left + 10 y = logo.top + 10 pyautogui.moveTo(x, y, 0.1) pyautogui.click() except AttributeError: logo = pyautogui.locateOnScreen('copy.png', confidence=0.8) x = logo.left + 10 y = logo.top + 10 pyautogui.moveTo(x, y, 0.1) pyautogui.click() if not bool(pyperclip.paste().strip()): moveTo(100, 70) click() time.sleep(4) ask() return command = "!" talk = "!talk" mute1 = "!mute" unmute1 = "!unmute" lastmessacommand = False stop = "!stop" def runspccmd(lastmessage): global command, talk, mute1, unmute1, lastmessacommand, current_unmute_thread if command in lastmessage: if talk in lastmessage: lastm = str(lastmessage) final = lastm.replace('<span>', "") final1 = final.replace('!talk', "") final2 = final1.replace('</span>', "") ask(final2) send(pyperclip.paste()) elif mute1 in lastmessage: if checkuserperms() == "no": print("skj") send("Scuze, n-ai permisiune pentru a face asta xx") return else: lastm = str(lastmessage) final = lastm.replace('<span>', "") final1 = final.replace('!mute', "") final2 = final1.replace('</span>', "") split = final2.split(" ", 3) print(split) mute(split[1], split[2], split[3]) elif stop in lastmessage: if checkuserperms() == "yes": send("Bot oprit ;( Ne mai vedem xx") sys.exit("Bot oprit") else: send("n-ai permisiune sa faci asta xx") elif unmute1 in lastmessage: if checkuserperms() == "yes": try: lastm = str(lastmessage) final = lastm.replace('<span>', "") final1 = final.replace('!unmute', "") final2 = final1.replace('</span>', "") split = final2.split(" ", 2) # 终止旧线程 if current_unmute_thread and current_unmute_thread.is_alive(): unmutestoploop.set() current_unmute_thread.join() # 启动新线程 current_unmute_thread = Thread(target=unmute, args=(int(split[2]), split[1])) current_unmute_thread.start() except IndexError: send("eroare, folosire comanda : !unmute nume timp(in secunde)") else: send("n-ai permisiune sa faci asta xx") else: send("""Comanda necunoscuta. Comenzi: !talk intrebare !mute nume secunde motiv !unmute nume secunde !stop""") def getlastmessage(): lm = pyperclip.paste() final = lm.replace('<span>', "") final2 = final.replace('</span>', "") print(final2) if "!" in final2: runspccmd(final2) pyautogui.moveTo(689, 877, 0.1) time.sleep(0.2) pyautogui.rightClick() time.sleep(0.2) pyautogui.moveTo(700, 850, 0.1) pyautogui.click() time.sleep(0.2) pyautogui.keyDown("F2") time.sleep(0.2) pyautogui.keyUp("F2") time.sleep(0.2) pyautogui.hotkey('ctrl', 'a') time.sleep(0.2) pyautogui.hotkey('ctrl', 'c') time.sleep(0.2) pyautogui.moveTo(1900, 140,0.1) pyautogui.click() while True: while not unmutestoploop.is_set(): time.sleep(1.2) pyautogui.moveTo(1000, 600) pyautogui.scroll(-600) getlastmessage()
修正后的最小复现代码
import time from threading import Thread, Event unmutestoploop = Event() current_unmute_thread = None # 存储当前线程 def unmute(time34=1, name1="test"): print(f"{name1} will get unmuted in {time34}s") global unmutestoploop # 循环检查终止信号 remaining_time = time34 while remaining_time > 0 and not unmutestoploop.is_set(): time.sleep(1) remaining_time -= 1 if unmutestoploop.is_set(): unmutestoploop.clear() print(f"{name1}'s unmute thread was stopped") return print(f"{name1} si-a luat unmute") def mute(name, time2, reason="None"): global current_unmute_thread # 终止旧线程 if current_unmute_thread and current_unmute_thread.is_alive(): unmutestoploop.set() current_unmute_thread.join() current_unmute_thread = Thread(target=unmute, args=(int(time2), "JJ")) current_unmute_thread.start() while True: while not unmutestoploop.is_set(): time.sleep(1) input2 = input("mute or unmute?") print("while loop working") if input2.lower() == "mute": mute("JJ", 5) else: # 终止旧线程再启动新线程 if current_unmute_thread and current_unmute_thread.is_alive(): unmutestoploop.set() current_unmute_thread.join() current_unmute_thread = Thread(target=unmute, args=(int(1), "Person")) current_unmute_thread.start()
内容的提问来源于stack exchange,提问作者Benioriginalul
相关产品推荐
相关产品推荐

