pywhatkit.sendwhatmsg无法发送消息,Tkinter GUI问题排查
问题分析与解决方案:AldiChat无法批量发送WhatsApp消息
问题概述
我开发了一款基于Tkinter的AldiChat GUI程序,用于通过pywhatkit批量发送WhatsApp消息。程序可正常读取CSV文件中的手机号并展示,但点击发送按钮后无法成功发送消息,控制台无任何报错。单独测试pywhatkit.sendwhatmsg的示例代码可正常运行,怀疑问题出在GUI相关逻辑或send_whatsapp_message函数中。
核心发送函数代码:
def send_whatsapp_message(): selected_numbers = numbers_listbox.curselection() message = message_entry.get() for index in selected_numbers: number = numbers_listbox.get(index) kit.sendwhatmsg(f'+{number}', message, 0, 0) # 立即发送
我通过f-string为手机号添加+号(格式从39XXXXXXXXXX转为+39XXXXXXXXXX),尝试直接指定号码也无法生效。请问是否是GUI导致的问题?
完整代码如下:
import tkinter as tk from tkinter import filedialog import pywhatkit as kit import csv def open_csv_file(): file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")]) if file_path: with open(file_path, 'r') as file: reader = csv.reader(file) for row in reader: numbers_listbox.insert(tk.END, row[0]) # 假设手机号在第一列 def send_whatsapp_message(): selected_numbers = numbers_listbox.curselection() message = message_entry.get() for index in selected_numbers: number = numbers_listbox.get(index) kit.sendwhatmsg(f'+{number}', message, 0, 0) # 立即发送 # 清空消息输入框 message_entry.delete(0, tk.END) def browse_file(): file_path = filedialog.askopenfilename() if file_path: attached_file_label.config(text=file_path) # 创建主窗口 root = tk.Tk() root.title("AldiChat") # 消息标签和输入框 message_label = tk.Label(root, text="输入消息:") message_label.pack() message_entry = tk.Entry(root, width=40) message_entry.pack() # 打开CSV文件按钮 open_csv_button = tk.Button(root, text="打开联系人文件", command=open_csv_file) open_csv_button.pack() # CSV中的手机号列表框 numbers_listbox = tk.Listbox(root, selectmode=tk.MULTIPLE) numbers_listbox.pack() # 立即发送WhatsApp消息按钮 send_button = tk.Button(root, text="立即发送WhatsApp消息", command=send_whatsapp_message) send_button.pack() # 附加文件按钮 attach_file_button = tk.Button(root, text="附加文件", command=browse_file) attach_file_button.pack() # 显示附加文件路径的标签 attached_file_label = tk.Label(root, text="") attached_file_label.pack() # 启动GUI root.mainloop()
问题原因分析
- Tkinter主线程阻塞:
pywhatkit.sendwhatmsg会启动浏览器并执行一系列操作,这个过程会占用主线程,导致Tkinter GUI冻结,同时可能因为主线程被阻塞,导致pywhatkit的操作无法正常完成。 - 时间参数错误:
sendwhatmsg传入的0,0会被解析为午夜12点,并非“立即发送”。pywhatkit的立即发送需要使用专门的方法,或计算当前时间加1分钟(给WhatsApp Web留加载时间)。 - 号码格式不规范:CSV中的号码可能包含空格、换行符等无效字符,导致格式不符合WhatsApp要求。
- 无错误捕获机制:代码没有异常捕获逻辑,即使pywhatkit内部出错,控制台也不会输出报错信息,无法定位问题。
解决方案
1. 用多线程避免GUI阻塞
将发送逻辑放到子线程中执行,防止阻塞Tkinter主线程:
import threading def send_whatsapp_message(): selected_numbers = numbers_listbox.curselection() message = message_entry.get() # 子线程执行发送逻辑 def send_thread(): for index in selected_numbers: number = numbers_listbox.get(index).strip().replace(' ', '') # 清洗号码 try: # 使用立即发送方法 kit.sendwhatmsg_instantly(f'+{number}', message, wait_time=15) except Exception as e: print(f"发送失败到号码 {number}: {str(e)}") # 回到主线程清空输入框 root.after(0, lambda: message_entry.delete(0, tk.END)) # 启动子线程 threading.Thread(target=send_thread, daemon=True).start()
2. 修正时间参数问题
- 使用
kit.sendwhatmsg_instantly()方法实现立即发送,该方法无需指定时间,只需设置等待时间(默认15秒,给WhatsApp Web加载时间)。 - 若坚持使用
sendwhatmsg,需传入当前时间并将分钟加1(pywhatkit要求至少1分钟准备时间):from datetime import datetime now = datetime.now() kit.sendwhatmsg(f'+{number}', message, now.hour, now.minute + 1)
3. 规范号码格式
读取CSV时清洗号码,去除多余字符:
def open_csv_file(): file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")]) if file_path: with open(file_path, 'r') as file: reader = csv.reader(file) for row in reader: if row[0]: cleaned_number = row[0].strip().replace(' ', '') numbers_listbox.insert(tk.END, cleaned_number)
4. 添加异常捕获
在发送逻辑中加入try-except块,打印错误信息便于排查:
try: kit.sendwhatmsg_instantly(f'+{number}', message) except Exception as e: print(f"发送错误: {e}")
最终修改后的核心发送函数
import threading from datetime import datetime def send_whatsapp_message(): selected_numbers = numbers_listbox.curselection() message = message_entry.get() def send_thread(): for index in selected_numbers: number = numbers_listbox.get(index).strip().replace(' ', '') if not number: continue full_number = f'+{number}' try: kit.sendwhatmsg_instantly(full_number, message, wait_time=15) print(f"消息已发送到 {full_number}") except Exception as e: print(f"发送到 {full_number} 失败: {str(e)}") root.after(0, lambda: message_entry.delete(0, tk.END)) threading.Thread(target=send_thread, daemon=True).start()
内容的提问来源于stack exchange,提问作者Daniele Intra
相关产品推荐
相关产品推荐

