> 文档中心 > C#Winform实战获取TIM消息

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也是同样的操作方式,甚至还可以做到抢红包,消息回复等,更多功能交给小伙伴们自行挖掘了!