C#Winform实战获取TIM消息
目录
前言
一、采集思路是什么?
二、怎么样使用软件去实时进行采集?
1.模拟人工去窗口执行全选复制的操作
2.软件解析剪切板聊天内容
3.数据清洗输出到可视化页面
总结
前言
提示: 本文仅用于学习分享,禁止用于任何违法行为,如有侵权,请联系删除。
如题,本篇文章将对TIM消息进行实时采集,优点简单易懂,不需要了解汇编与逆向,基本没有封号风险,缺点是占用键盘鼠标,下面直接上演示图片
一、采集思路是什么?
看了前言的GIF图的小伙伴不难看出直接在聊天窗中采集到了聊天数据,包括有时间,发送人,以及内容,最关键的思路是利用了剪切板
当我们在聊天窗使用ctrl+a+c,然后在发送框中粘贴,会发现粘贴的内容是一种特殊的格式进行显示,可以判断出剪切板中可以拿到聊天的数据内容
这里通过代码对剪切板内的内容进行分析,得到8个格式化的类型,对这8个类型逐一分析,举例其中Text格式化方式可以拿到聊天数据,但是缺少了图片的信息,经过我逐一的测试,最终 QQ_Msg_RichEdit_Format 的格式方式可以拿到比较完善的数据,感兴趣的小伙伴可以自己尝试一下。那最核心的采集部分就完结了。
二、怎么样使用软件去实时进行采集?
知道了核心的采集步骤,我们的采集思路是 模拟人工去窗口执行全选复制的操作->软件解析剪切板聊天内容->数据进行清洗输出到可视化页面
1.模拟人工去窗口执行全选复制的操作
1) 第一步我们需要拿到聊天窗口的句柄,通过窗口名称或者进程ID进行获取,这里要注意,一定要把聊天窗口双击点出单独的页面来!
代码如下(示例):
IntPtr FindTarget(string monitorContent) { var pid = 0; IntPtr hwndRel = IntPtr.Zero; int.TryParse(monitorContent, out pid); if (pid > 0) { hwndRel = Process.GetProcessById(pid).MainWindowHandle; } if (pid <= 0 || hwndRel == null || hwndRel == IntPtr.Zero) { hwndRel = WindowsAPI.FindWindow(null, monitorContent); } return hwndRel; }
2)第二步我们需要通过Windows API去执行模拟操作
模拟点击,模拟全选复制,代码如下(示例):
WindowsAPI.SetForegroundWindow(hwnd);//置顶聊天窗 RECT rECT = new RECT(); WindowsAPI.GetWindowRect(hwnd, ref rECT);//获取句柄位置 //获取聊天窗内容 偏移点击 var x = rECT.left + 250; var y = rECT.top + 150; WindowsAPI.SetCursorPos(x, y);//设置鼠标位置 WindowsAPI.mouse_event(WindowsAPI.MouseEventFlag.LeftDown, 0, 0, 0, 0); //模拟鼠标按下操作 WindowsAPI.mouse_event(WindowsAPI.MouseEventFlag.LeftUp, 0, 0, 0, 0);//模拟鼠标放开操作 //全选复制操作 WindowsAPI.keybd_event(WindowsAPI.VirtualKeyCode.CTRL_key, 0, 0, 0); WindowsAPI.keybd_event(WindowsAPI.VirtualKeyCode.A_key, 0, 0, 0); WindowsAPI.keybd_event(WindowsAPI.VirtualKeyCode.A_key, 0, 2, 0); WindowsAPI.keybd_event(WindowsAPI.VirtualKeyCode.C_key, 0, 0, 0); WindowsAPI.keybd_event(WindowsAPI.VirtualKeyCode.C_key, 0, 2, 0); WindowsAPI.keybd_event(WindowsAPI.VirtualKeyCode.CTRL_key, 0, 2, 0);
2.软件解析剪切板聊天内容
代码如下(示例):
IDataObject data = Clipboard.GetDataObject(); if (data != null) { var stream = (Stream)data.GetData("QQ_Unicode_RichEdit_Format", false); using (var streamReader = new StreamReader(stream)) { var str = streamReader.ReadToEnd(); var md5 = GetMD5(str); var dto = new UpcomingMessageDTO { Hwnd = hwnd, Message = str, MD5 = md5 }; if (UpcomingMessage.Contains(dto) == false) { UpcomingMessage.Enqueue(dto); } } stream.Dispose(); stream.Close(); }
3.数据清洗输出到可视化页面
通过以上步骤从剪切板内容拿到了一串XML数据
处理比较麻烦,我把这一串XML数据转成了Json数据
从这串Json中不难发现聊天内容已经可以拿到,但是有不同的消息内容,@type这个字段主要标识消息内容的,经过测试分析0为文本内容,1为图片,并且聊天内容会有多条拼接的情况,我们需要对拼接的数据进行拆解分析。我们拿出某一个拼接的聊天记录,利用正则进行匹配输出,如图
最后通过正则 (\S+)\s([0-9]{2}:[0-5][0-9]:[0-5][0-9])\r\n(.+|.*?) 拿到了匹配的消息内容,当然这个正则可能还有点问题,有更严谨的小伙伴自行进行测试分析了,通过正则分组拿到了昵称,时间,内容,再通过时间以及昵称进行去重,就可以在页面上呈现出来了。
代码如下(示例):
/// /// 数据清洗 /// void ProcessMessage() { Task.Factory.StartNew(async () => {while (true){ try { if (UpcomingMessage.Count > 0) { var message = UpcomingMessage.Dequeue(); //xml数据转json var doc = new XmlDocument(); doc.LoadXml(message.Message); string json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(doc); //反序列化json数据 var timMessage = Newtonsoft.Json.JsonConvert.DeserializeObject(json); var length = timMessage.QQRichEditFormat.EditElement.Count; if (length > 0) { var outTimMessage = new List(); for (int i = 0; i 0){ foreach (Match msg in msgs) { var index = msg.Index; var valueLen = msg.Value.Length; var sender = msg.Groups[1].Value; var time = msg.Groups[2].Value; var sendMessage = msg.Groups[3].Value; if (i == 0 && index > 0 && lastMsgItem != null)//消息拼接 { lastMsgItem.SendMessage = lastMsgItem.SendMessage + sendMessage; } else { if (Message.Where(x => x.Hwnd == message.Hwnd && x.SendTime == time).Any() == false) { outTimMessage.Add(new OutTimMessage { SendTime = time, Hwnd = message.Hwnd, SendMessage = sendMessage, Sender = sender }); } } }} } else {Console.WriteLine($"暂未支持解析类型{Newtonsoft.Json.JsonConvert.SerializeObject(item)}"); } } } Message.AddRange(outTimMessage); foreach (var item in outTimMessage) { //输出消息 AppandLogs($"收到消息:{item.Sender},{item.SendTime},{item.SendMessage}", LogLevel.Info); } } } } catch (Exception ex) { AppandLogs("消息处理出错!", LogLevel.Error); return; } await Task.Delay(1000);} }, TaskCreationOptions.LongRunning); }
这里数据去重采用了正序,更好的方案应该采用逆序进行去重更加高效,感兴趣的朋友可自行摸索测试了!
以上用到的WinApi链接:Windows API
下面附上懒人链接:资源地址
总结
从本篇文章可以了解到TIM聊天信息的采集思路,以及数据的清洗去重展示,那同样QQ也是同样的操作方式,甚至还可以做到抢红包,消息回复等,更多功能交给小伙伴们自行挖掘了!