Files
weixin-holiday-message/auto_send_blessing.py

271 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
微信自动发送祝福语脚本
功能:
1. 从API获取已选联系人的搜索姓名和祝福语
2. 自动搜索联系人、发送祝福语
3. 发送完成后更新前端状态
4. 按 F9 停止运行
"""
import os
import sys
import time
import json
import threading
import requests
import pyautogui
import pyperclip
from ctypes import windll, c_long
# 坐标配置
SEARCH_BOX_X, SEARCH_BOX_Y = 1933, 39
SEARCH_RESULT_X, SEARCH_RESULT_Y = 2009, 100
CHAT_INPUT_X, CHAT_INPUT_Y = 2160, 1173
# API配置
API_BASE = 'http://localhost:5000/api'
# 全局停止标志
stop_flag = False
stop_lock = threading.Lock()
def get_selected_contacts():
"""获取已选择的联系人"""
try:
response = requests.get(f'{API_BASE}/contacts?page=1&page_size=1000', timeout=10)
data = response.json()
selected = [c for c in data.get('contacts', []) if c.get('selected')]
return selected
except Exception as e:
print(f"获取联系人失败: {e}")
return []
def update_contact_sent(contact_id):
"""更新联系人发送状态"""
try:
requests.put(
f'{API_BASE}/contacts/{contact_id}',
json={'selected': False},
timeout=10
)
return True
except Exception as e:
print(f"更新状态失败: {e}")
return False
def check_stop():
"""检查是否需要停止"""
with stop_lock:
return stop_flag
def set_stop():
"""设置停止标志"""
with stop_lock:
global stop_flag
stop_flag = True
print("\n收到停止信号,正在停止...")
def get_current_key():
"""获取当前按下的键"""
try:
# 使用windll获取按键状态
# F9 = 0x78 (120)
if windll.user32.GetAsyncKeyState(0x78) & 0x8000:
return 'F9'
except:
pass
return None
def wait_for_key_press():
"""监听F9按键"""
global stop_flag
import keyboard
try:
keyboard.add_hotkey('F9', set_stop)
print("提示: 按 F9 可随时停止运行")
except ImportError:
print("警告: keyboard库未安装无法使用F9停止功能")
print("请运行: pip install keyboard")
def send_blessing_to_contact(search_name, blessing):
"""发送祝福语给单个联系人"""
if check_stop():
return False, "已停止"
try:
# 1. 点击搜索框
print(f" → 点击搜索框 ({SEARCH_BOX_X}, {SEARCH_BOX_Y})")
pyautogui.moveTo(SEARCH_BOX_X, SEARCH_BOX_Y, duration=0.3)
pyautogui.click()
time.sleep(0.5)
if check_stop():
return False, "已停止"
# 2. 清空搜索框并输入名字
print(f" → 输入名字: {search_name}")
pyautogui.hotkey('ctrl', 'a')
time.sleep(0.2)
pyperclip.copy(search_name)
pyautogui.hotkey('ctrl', 'v')
time.sleep(1)
if check_stop():
return False, "已停止"
# 3. 点击搜索结果
print(f" → 点击搜索结果 ({SEARCH_RESULT_X}, {SEARCH_RESULT_Y})")
pyautogui.moveTo(SEARCH_RESULT_X, SEARCH_RESULT_Y, duration=0.3)
pyautogui.click()
time.sleep(1)
if check_stop():
return False, "已停止"
# 4. 点击聊天输入框
print(f" → 点击聊天输入框 ({CHAT_INPUT_X}, {CHAT_INPUT_Y})")
pyautogui.moveTo(CHAT_INPUT_X, CHAT_INPUT_Y, duration=0.3)
pyautogui.click()
time.sleep(0.5)
if check_stop():
return False, "已停止"
# 5. 输入祝福语
print(f" → 输入祝福语...")
pyperclip.copy(blessing)
pyautogui.hotkey('ctrl', 'v')
time.sleep(0.5)
if check_stop():
return False, "已停止"
# 6. 发送
print(f" → 发送消息")
pyautogui.press('enter')
time.sleep(0.5)
return True, "发送成功"
except Exception as e:
return False, f"发送失败: {str(e)}"
def main():
global stop_flag
print("=" * 60)
print("微信自动发送祝福语脚本")
print("=" * 60)
print()
print("配置信息:")
print(f" 搜索框坐标: ({SEARCH_BOX_X}, {SEARCH_BOX_Y})")
print(f" 搜索结果坐标: ({SEARCH_RESULT_X}, {SEARCH_RESULT_Y})")
print(f" 聊天输入框坐标: ({CHAT_INPUT_X}, {CHAT_INPUT_Y})")
print()
# 尝试导入keyboard库用于F9停止
try:
import keyboard
keyboard.add_hotkey('F9', set_stop)
print("✓ F9 停止功能已启用")
except ImportError:
print("✗ keyboard库未安装F9停止功能不可用")
print(" 请运行: pip install keyboard")
except Exception as e:
print(f"✗ keyboard库加载失败: {e}")
print()
# 获取已选联系人
print("正在获取已选联系人...")
contacts = get_selected_contacts()
if not contacts:
print("没有找到已选择的联系人!")
print("请在前端页面勾选要发送的联系人,然后重试。")
return
print(f"找到 {len(contacts)} 个已选联系人:")
print("-" * 60)
for i, c in enumerate(contacts, 1):
print(f" {i}. {c.get('name', '未知')} (搜索名: {c.get('search_name', '')})")
print("-" * 60)
print()
# 确认开始
print("准备开始发送祝福语...")
print("请在 5 秒内切换到微信窗口!")
print()
# 等待用户准备
for i in range(5, 0, -1):
if check_stop():
print("已取消运行")
return
print(f" {i}...")
time.sleep(1)
print()
print("开始发送祝福语...")
print("=" * 60)
success_count = 0
fail_count = 0
skip_count = 0
for i, contact in enumerate(contacts, 1):
if check_stop():
print("\n用户停止运行")
break
name = contact.get('name', '未知')
search_name = contact.get('search_name') or contact.get('name', '')
blessing = contact.get('blessing', '')
contact_id = contact.get('id')
print(f"\n[{i}/{len(contacts)}] 发送给: {name}")
print(f" 搜索名: {search_name}")
if len(blessing) > 50:
print(f" 祝福语: {blessing[:50]}...")
else:
print(f" 祝福语: {blessing}")
# 检查祝福语是否为空
if not blessing:
print(f" ⚠ 跳过: 祝福语为空")
skip_count += 1
continue
# 发送祝福语
success, message = send_blessing_to_contact(search_name, blessing)
if success:
print(f" ✓ 发送成功")
success_count += 1
# 更新前端状态
if update_contact_sent(contact_id):
print(f" ✓ 已更新前端状态")
else:
print(f" ✗ 更新前端状态失败")
# 发送间隔
time.sleep(1)
else:
print(f"{message}")
fail_count += 1
if not check_stop():
time.sleep(2)
print()
print("=" * 60)
print("发送完成!")
print("=" * 60)
print(f" 成功: {success_count}")
print(f" 失败: {fail_count}")
print(f" 跳过: {skip_count}")
print()
if __name__ == '__main__':
main()