整理 | 小耕家的喵大仙
出品 | CSDN(ID:lichao19897314)
Q Q | 978124155
关于项目背景和微信自动化学习介绍
因为前面写了很多关于微信自动化的文章,网上有一位网友说他是做培训行业的,有时候除了微信对接客户还需要通过QQ来做日常的回复工作,因为很多回复是重复性,他想实现监听QQ消息并自动回复文字内容和文件的功能。该篇博客记录了实现QQ自动回复的整体实现逻辑和技术细节。
如果有兴趣的朋友可以看下我微信自动化的文章!因为底层实现和微信自动化同根同源,感兴趣的点个赞关注支持下原创。
(1)微信UI自动化-篇章开启(C#)
(2)微信UI自动化-微信窗体管理(C#)
(3)微信UI自动化-热键管理(C#)
(4)微信UI自动化-联系人采集(C#)
(5)微信UI自动化-实现静默鼠标点击(C#)
(6)微信UI自动化-搜索指定联系人(C#)
(7)微信UI自动化-自动发送消息给指定联系人(C#)(.Net)
(8)微信UI自动化-监控微信进程运行状态(C#)
(9)微信UI自动化-监控微信网络状态(C#)
(10)微信UI自动化-跟随微信窗口移动(C#)
(11)微信UI自动化-微信窗口跟随主窗体移动(C#)
(12)PC端微信自动化测试-C#采集微信聊天记录
(13)PC端微信自动化UI-C#监听微信消息自动回复
(14)微信自动化测试-针对微信控件元素截图操作
(15)微信自动化测试-针对微信主窗体的行为控制
(16)微信自动化测试-C#控制微信多开
-
QQ版本以及软件功能效果
采用的QQ版本为当前最新版本QQ👇
QQ监听消息并自动回复的效果视频呈现
QQ监听消息自动回复
实时监听最新消息并根据消息内容给指定联系人做回复(包括回复文本和文件)
-
技术实现思路和示例代码
- 找到QQ主窗体句柄和QQ进程ID,通过QQ进程ID构建UIA3Automation的自动化测试实例。
- 构建针对QQ自动化测试实例成功后,我们创建一个后台监听任务,监听QQ主窗体的消息面板。监听任务判断消息面板中的UI对象中的内容是否有修改,如果有修改则判断为新消息。
- 因为本次程序是针对特定群和特定联系人的自动回复,所以需要将特定群或者联系人的聊天窗口平铺打开。请像如下打开需要监听的联系人聊天窗口
- 通过监听任务获取到的新消息内容和消息发送人,通过UI自动化实例对象找到与对应联系人的聊天窗口。
- 找到对应的聊天窗口的编辑框和发送按钮的UI对象实例。
- 通过监听到的消息内容产生我们自己需要回复的智能化业务内容,并通过剪贴版本的方式复制到聊天窗口的编辑框中,执行发送按钮的点击事件,完成发送,并将新消息内容设为以处理。
核心示例代码
加载QQ主窗体并构建自动化测试实例
public bool Load()
{
int weChatID = 0;
IntPtr hwnd = FindWindow(null, "QQ");
if (hwnd != IntPtr.Zero)
{
GetWindowThreadProcessId(hwnd, out weChatID);
}
else
{
return false;
}
application = FlaUI.Core.Application.Attach(weChatID);
automation = new UIA3Automation();
Window = application.GetMainWindow(automation);
var windowSource = application.GetAllTopLevelWindows(automation);
if (Window == null)
return false;
startPanel = string.Format("/Pane[{0}]", Window.FindAllChildren().Length-1);
return true;
}
监控实例对象
using FlaUI.WinForm.UIAuto.Business.WX.Task.Base;
using FlaUI.WinForm.UIAuto.Model;
using OnlineRetailers.Extension.Page.UIAuto;
using OnlineRetailers.Extension.Page.UIAuto.Log;
using OnlineRetailers.Extension.Page.UIAuto.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace FlaUI.WinForm.UIAuto.Business.WX.Task
{
public class UI_Real_Reply_Task : UI_QQ_Element_Base_Task
{
private List<QQRealMsgEntity> historyMessageSource { get; set; }
/// <summary>
/// 自动回复内容
/// </summary>
public string ReplyMessage { get; set; }
/// <summary>
/// 自动回复文件的文件路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 需要自动回复的用户
/// </summary>
public List<string> ReplyUser { get; set; }
public override void Stop()
{
base.Stop();
}
public override void Start()
{
if (State == TaskState.Stop)
{
State = TaskState.Runing;
}
else
{
return;
}
Thread th = new Thread(new ThreadStart(() =>
{
while (State == TaskState.Runing)
{
var currentChatList = UI_QQ_Window.Current.Find("主窗体消息面板UI");
if (currentChatList == null || currentChatList.ControlType != FlaUI.Core.Definitions.ControlType.Pane)
{
Thread.Sleep(1000);
continue;
}
var source = currentChatList.FindAllChildren();
var tempMessageSource = new List<QQRealMsgEntity>();
source.ToList().ForEach(item =>
{
if (item.ControlType == FlaUI.Core.Definitions.ControlType.ListItem)
{
var buttonName = item .Name;
var lastMessage = item.Patterns.Value.PatternOrDefault?.Value;
var messageitem = new QQRealMsgEntity { UserName = buttonName, CurrentMessage = lastMessage };
tempMessageSource.Add(messageitem);
if (historyMessageSource != null)
{
var cnt = historyMessageSource.Count(s => s.UserName == messageitem.UserName && messageitem.CurrentMessage == s.CurrentMessage);
if (cnt == 0)
{
//有新消息
SetMessage(messageitem.UserName + "发送给新消息你:" + messageitem.CurrentMessage);
if (ReplyUser.Count(ss => ss.Contains(messageitem.UserName)) > 0 )
{
if (!string.IsNullOrEmpty(FilePath))
{
if (
!messageitem.CurrentMessage.Contains("对方已成功接收了你发送的离线文件")
&& !messageitem.CurrentMessage.Contains("[图片文件]")
&& !messageitem.CurrentMessage.Contains("已成功保存至文件助手"))//正对自己发送的图片文件不采取回复,有可能发送文件
{
if ( SendQQFile(messageitem.UserName, FilePath))
{
SetMessage("自动回复文本消息给" + messageitem.UserName + ":" + ReplyMessage);
//var fileName = System.IO.Path.GetFileName(FilePath);
}
}
}
if (!string.IsNullOrEmpty(ReplyMessage))
{
if ( SendQQText(messageitem.UserName, ReplyMessage))
{
SetMessage("自动回复文件消息给" + messageitem.UserName + ":" + ReplyMessage);
messageitem.CurrentMessage = ReplyMessage;
}
}
}
}
}
}
});
historyMessageSource = tempMessageSource;
Thread.Sleep(500);
}
}));
th.Start();
base.Start();
}
public bool SendQQText(string name, string message)
{
return SendQQMessage(name, new QQMessageEntity { Info = message, Type = QQMessageType.Text });
}
public bool SendQQFile(string name, string filePath) {
return SendQQMessage(name, new QQMessageEntity { Info = filePath, Type = QQMessageType.File });
}
public bool SendQQMessage(string name, QQMessageEntity message) {
//查找窗体
var currentChatWindow = UI_QQ_Window.Current.GetCurrentChatWindow(name);
if (currentChatWindow != null)
{
var SendInput = currentChatWindow.FindFirstByXPath("聊天窗体编辑框");// GetSendInput();
var SendButton = currentChatWindow.FindFirstByXPath("聊天窗体发送按钮");// GetSendInput();
if (SendInput == null)
{
SystemLog.Error("【" + name + "】窗体下未找到输入框,发送信息失败");
}
if (SendButton == null)
{
SystemLog.Error("【" + name + "】窗体下未找到发送按钮,发送信息失败");
}
currentChatWindow.Focus();
SetText(message, SendInput, false);
UI_QQ_Window.Current.ClickElement(SendButton, currentChatWindow);
SystemLog.Info("向【" + name + "】窗体发送信息" + message.Info + "成功");
return true;
}
else
{
SystemLog.Error("【" + name + "】窗体未找到,发送信息失败");
}
return false;
}
}
}
以上是核心组件及代码思路,因为代码关联类比较多,无法在本篇全部博客呈现!如果需要源码请加本人QQ 978124155