C# 获取QQ群数据的实现

转载 2018年04月16日 14:03:29

原文链接:点击打开链接

摘要: 一,分析 1,群数据获取         当访问http://qun.qq.com/air/#mygroup我们通过Fiddler可以查看到QQ群列表是从http://qun.qq.com/air/group/mine?w=a这个URL获取到的群列表信息               其中返回的js...

一,分析

1,群数据获取

        当访问http://qun.qq.com/air/#mygroup我们通过Fiddler可以查看到QQ群列表是从http://qun.qq.com/air/group/mine?w=a这个URL获取到的群列表信息

          image

   其中返回的json数据,json构成如下

             image

          从上面我们可以看出c包含的是群列表信息,r包含的是服务器的信息,其中c的某一项构成如下图所示

                      

        从上面可以看出项名称就是群号,owner为所有者,name为群名称,memo群描述,brief为群公告信息,还有其他的一些信息,大家自己去匹配,我这里就不一一解释了.

   2, 单个群的成员获取,在上面我们分析了如何获取群列表,下面我们将分析如何取得单个群成员的数据 
      当我们点开某个群可以看到有查看通讯录的选项 
     image 
     此时我们通过Fiddler监视可以发现,群成员信息,通过如下地址取得 
           image 
    但是我经过几次点击测试,发现URL参数规则如下 
      image 
      贴出参数构造规则 
     

const string groupMemberUrl = "http://qun.qq.com/air/{0}/addr/index/type/1/p/{1}?w=n&_={2}";
string memberURL = string.Format(groupMemberUrl, gInfo.Number, page, JavascriptAction.Random());
  我们按照这样的地址去请求,就会得到QQ群成员的HTML,然后我在解析HTML就可以得到相应的数据了

二,实现 


    1, 获取群列表

        public List<GroupInfo> GetGroupInfos()
        {
            if (!isLogin) Login();
            List<GroupInfo> giList = new List<GroupInfo>();
            string json = GetWebData<string>(string.Format(groupListUrl, JavascriptAction.Random()));
            try
            {
                var jsonObj = JavaScriptEngine.Run("var m=" + json + ";m.c") as Dictionary<string, object>;
                foreach (var key in jsonObj.Keys)
                {
                    var gi = (jsonObj[key] as Dictionary<string, object>);
                    if (!gi.ContainsKey("owner")) continue;
                    string owner = gi["owner"].ToString();
                    string name = gi["name"].ToString();
                    string max_member = gi["max_member"].ToString();
                    string create_time = gi["create_time"].ToString();
                    string notice = gi["brief"].ToString();
                    string number = key;
                    string memo = gi["memo"].ToString();
                    giList.Add(new GroupInfo()
                    {
                        CreateTime = JavascriptAction.GetTimeByJsTime(Convert.ToInt64(create_time)),
                        MaxNumber = Convert.ToInt32(max_member),
                        Memo = memo,
                        Name = name,
                        Notice = notice,
                        Number = number,
                        Owner = owner
                    });
                }
            }
            catch { }
            return giList;
        }

         上面的函数实现了群列表的获取,需要说明的是获取到的json是同过javascript引擎来运行的,javascript运行我通过Javascript .NET(http://javascriptdotnet.codeplex.com/releases/view/52449)来实现的,获取web数据参考我的blog的另外的文章,文章有实现源代码,至于登陆我最后会说明

   2, 获取群成员 
      

        public List<QQGroupMemberInfo> GetMemberInfo(GroupInfo gInfo)
        {
            if (!isLogin) Login();
            List<QQGroupMemberInfo> gmis = new List<QQGroupMemberInfo>();
            int page = 1;
            int pageCount = 0;
        GETMEMBER:
            string memberURL = string.Format(groupMemberUrl, gInfo.Number, page, JavascriptAction.Random());
            string html = GetWebData<string>(memberURL);
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(html);
            if (pageCount < 1)
            {
                var seeBtn = doc.DocumentNode.SelectSingleNode(pageBtnPath);
                pageCount = Convert.ToInt32(seeBtn.Attributes["allpage"].Value);
            }
            var trs = doc.DocumentNode.SelectNodes(memberTrPath);
            foreach (var tr in trs)
            {
                var tds = tr.Descendants("td").ToList();
                if (tds.Count < 1) continue;
                string groupNick = tds[1].Element("a").InnerText.Trim();
                string qq = tds[2].Element("span").InnerText.Trim();
                gmis.Add(new QQGroupMemberInfo()
                {
                    NickName = groupNick,
                    QQ = qq
                });
            }
            if (page < pageCount)
            {
                page++;
                goto GETMEMBER;
            }
            return gmis;
        }

   上面的函数实现了群成员的获取,其中HTML的解析式通过HtmlAgilityPack(http://htmlagilitypack.codeplex.com/)来实现,HtmlAgilityPack通过XPATH语法去解析实现的,关于xpath不是很难,大家查查资料就会了 
   3,关于登陆的实现 
     QQweb端的登陆有两种实现,第一种是web登陆,通过http://ui.ptlogin2.qq.com/cgi-bin/login?link_target=blank&appid=15000101&hide_title_bar=1&s_url=http%3A%2F%2Fim.qq.com%2Floginproxy.html%3Flogin_level%3D2&f_url=loginerroralert&target=self这样的URL实现来实现登陆,具体的实现原理,我前面有文章描述过了,这里就不罗嗦了,把类贴出来供大家参考

    public class LoginQQ : WebPageAction, ILogin, IValidateCodeAction
    {
        static JavaScriptEngine _javaEngine = new JavaScriptEngine();
        static bool _isInitJava = false;
        Random _r = new Random();
        const string loginFormUrl = "http://ui.ptlogin2.qq.com/cgi-bin/login?link_target=blank&appid=15000101&hide_title_bar=1&s_url=http%3A%2F%2Fim.qq.com%2Floginproxy.html%3Flogin_level%3D2&f_url=loginerroralert&target=self";
        private User User { get; set; }
        string _qq = "";
        public LoginQQ(CookieManager cookieManager, User user)
            : base(user.UserName)
        {
            _cookieManager = cookieManager;
            User = user;
            _qq = user.UserName.Split('@')[0];
            if (!_isInitJava)
            {
                _javaEngine.Run(System.IO.File.ReadAllText(@"JavaScript\qq\md5_3.js"));
                _isInitJava = true;
            }
        }
 
        public override JavaScriptEngine JavaScriptEngine
        {
            get
            {
                return _javaEngine;
            }
            set
            {
                _javaEngine = value;
            }
        }
 
        string vc_type = "";
        public bool Login(string referer)
        {
            DateTime beginTime = DateTime.Now;
            string html = "";
            html = GetWebData<string>(loginFormUrl);
            if (!regForm.IsMatch(html))
                ThrowException(507, html);
            var form = GetFormDataByFormHtml(regForm.Match(html).Value);
            string url = "http://ptlogin2.qq.com/check?uin=" + _qq + "&appid=15000101&" + JavascriptAction.Random();
            html = GetWebData<string>(url, referer: loginFormUrl);
            string vcode = "";
            if (html.Contains("ptui_checkVC('1','"))
            {
                vc_type = html.Replace("ptui_checkVC('1','", "").Replace("'", "").Replace(")", "").Replace(";", "");
                form = new NameValueCollection();
                if (!ValidationImageCode(form, loginFormUrl)) { return false; };
                vcode = form["verifycode"];
            }
            else if (html.Contains("ptui_checkVC('0','"))
            {
                vcode = html.Replace("ptui_checkVC('0','", "").Replace("'", "").Replace(")", "").Replace(";", "");
            }
            TimeSpan _tspan = TimeSpan.FromTicks(DateTime.Now.Ticks - beginTime.Ticks);
            if (_tspan.Seconds < 20)
                Thread.Sleep(TimeSpan.FromSeconds(_r.Next(20 - _tspan.Seconds, 30)));
            string pMd5 = GetPwdString(User.Pwd, vcode);
            string action = "0-0" + "-" + (JavascriptAction.GetTime(DateTime.Now) - JavascriptAction.GetTime(beginTime));
            url = "http://ptlogin2.qq.com/login?u=" + _qq + "&p=" + pMd5 + "&verifycode=" + vcode + "&aid=15000101&u1=http%3A%2F%2Fim.qq.com%2Floginproxy.html%3Flogin_level%3D2&h=1&ptredirect=0&ptlang=2052&from_ui=1&dumy=&fp=loginerroralert&action=" + action + "&mibao_css=";
            html = GetWebData<string>(url, referer: loginFormUrl);
            if (html.Contains("登录成功"))
            {
                return true;
            }
            return false;
        }
 
        private string GetPwdString(string pwd, string vcode)
        {
            string script = "md5(md5_3('" + pwd + "') + '" + vcode + "')";
            return JavaScriptEngine.Run(script).ToString();
        }
 
        public bool ValidateLogin(string referer)
        {
            var cks = _cookieManager.GetCookies(new Uri(referer).Host);
            if (cks["uin"] != null && cks["skey"] != null)
            {
                return true;
            }
            return false;
        }
 
        public bool ValidationCode(string code, string referer)
        {
            return true;
        }
 
        public Image GetValidateCode(string referer)
        {
            string url = "http://captcha.qq.com/getimage?aid=15000101&r=" + JavascriptAction.Random() + "&uin=" + _qq + "&vc_type=" + vc_type;
            return GetWebData<Image>(url, referer: referer);
        }
 
        public bool ValidationImageCode(NameValueCollection customFormItems, string referer)
        {
            ValidateReturn code = null;
            do
            {
                Image image = GetValidateCode(referer);
                code = this.FireValidateCode(image);
                if (code.IsCancel)
                {
                    return false;
                }
                if (customFormItems.AllKeys.Contains("verifycode"))
                {
                    customFormItems.Remove("verifycode");
                }
                customFormItems.Add("verifycode", code.Code);
            }
            while (code.IsChange || !ValidationCode(code.Code, referer));
            return true;
        }
 
 
    }

第二种就是从客户端点击,如QQ空间按钮,客户端会调用浏览器跳转

http://ptlogin2.qq.com/jump?ptlang=2052&clientuin=442799037&clientkey=687E58BB1B99061A S62F0C751CF1763F1A8EEA3E8F2AF52B7956193D947F78B6&u1=http%3A%2F%2Fuser.qzone.qq.com%2F442799037%2Finfocenter&ADUIN=442799037&ADSESSION=1335488190&ADTAG=CLIENT.QQ.3187_Mysrv.0这样的地址,通过这个URL实现登陆,那么我们只需要HOOK ShellExecuteExW这个入口点就可以实现URL的截取,关于钩子如何实现,我前面有文章已说过,同样贴上代码供大家参考 

    public class ClientQQWebction : WebPageAction, IDisposable
    {
        const string loginUrl = "http://ptlogin2.qq.com/jump?ptlang={2}&clientuin={0}&clientkey={1}&u1={3}";
        const string getEmail = "http://accountadm.qq.com/cgi-bin/account/ajaxgetmail?uin={0}";
        const string groupListUrl = "http://qun.qq.com/air/group/mine?w=a&_={0}";
        const string groupMemberUrl = "http://qun.qq.com/air/{0}/addr/index/type/1/p/{1}?w=n&_={2}";
        const string pageBtnPath = "//input[@type=\"button\" and @value=\"查看\" and @act=\"gotopage\"]";
        const string memberTrPath = "//table[@class=\"addressList\"]/tr";
 
        CleintKeyInfo _cleintKeyInfo = null;
        bool isLogin = false;
        public ClientQQWebction(CleintKeyInfo cki)
        {
            _cleintKeyInfo = cki;
        }
 
        private void Login()
        {
            string loginURL = string.Format(loginUrl, _cleintKeyInfo.ClientUin, _cleintKeyInfo.ClientKey, _cleintKeyInfo.PtLang, string.Format(getEmail, _cleintKeyInfo.ClientUin));
            var loca = GetWebData<ResponseLocation>(loginURL);
            if (_cookieManager.GetCookies("qq.com")["skey"] != null)
            {
                isLogin = true;
                return;
            }
            throw new Exception("登陆失败");
        }
 
        public string GetEmail()
        {
            if (!isLogin) Login();
            string emailUrl = String.Format(getEmail, _cleintKeyInfo.ClientUin);
            var html = GetWebData<string>(emailUrl);
            if (regEmail.IsMatch(html))
                return regEmail.Match(html).ToString();
            else
                return null;
        }
 
        public List<GroupInfo> GetGroupInfos()
        {
            if (!isLogin) Login();
            List<GroupInfo> giList = new List<GroupInfo>();
            string json = GetWebData<string>(string.Format(groupListUrl, JavascriptAction.Random()));
            try
            {
                var jsonObj = JavaScriptEngine.Run("var m=" + json + ";m.c") as Dictionary<string, object>;
                foreach (var key in jsonObj.Keys)
                {
                    var gi = (jsonObj[key] as Dictionary<string, object>);
                    if (!gi.ContainsKey("owner")) continue;
                    string owner = gi["owner"].ToString();
                    string name = gi["name"].ToString();
                    string max_member = gi["max_member"].ToString();
                    string create_time = gi["create_time"].ToString();
                    string notice = gi["brief"].ToString();
                    string number = key;
                    string memo = gi["memo"].ToString();
                    giList.Add(new GroupInfo()
                    {
                        CreateTime = JavascriptAction.GetTimeByJsTime(Convert.ToInt64(create_time)),
                        MaxNumber = Convert.ToInt32(max_member),
                        Memo = memo,
                        Name = name,
                        Notice = notice,
                        Number = number,
                        Owner = owner
                    });
                }
            }
            catch { }
            return giList;
        }
 
      
        public List<QQGroupMemberInfo> GetMemberInfo(GroupInfo gInfo)
        {
            if (!isLogin) Login();
            List<QQGroupMemberInfo> gmis = new List<QQGroupMemberInfo>();
            int page = 1;
            int pageCount = 0;
        GETMEMBER:
            string memberURL = string.Format(groupMemberUrl, gInfo.Number, page, JavascriptAction.Random());
            string html = GetWebData<string>(memberURL);
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(html);
            if (pageCount < 1)
            {
                var seeBtn = doc.DocumentNode.SelectSingleNode(pageBtnPath);
                pageCount = Convert.ToInt32(seeBtn.Attributes["allpage"].Value);
            }
            var trs = doc.DocumentNode.SelectNodes(memberTrPath);
            foreach (var tr in trs)
            {
                var tds = tr.Descendants("td").ToList();
                if (tds.Count < 1) continue;
                string groupNick = tds[1].Element("a").InnerText.Trim();
                string qq = tds[2].Element("span").InnerText.Trim();
                gmis.Add(new QQGroupMemberInfo()
                {
                    NickName = groupNick,
                    QQ = qq
                });
            }
            if (page < pageCount)
            {
                page++;
                goto GETMEMBER;
            }
            return gmis;
        }
 
 
        public void Dispose()
        {
            _cookieManager = null;
 
            JavaScriptEngine = null;
 
        }
    }

OK,到此完成,下篇实现qq好友数据获取


用C#实现封装

-
  • 1970年01月01日 08:00

c#实现QQ群成员列表导出及邮件群发开篇

前言 随之互联网的发展,网上营销的手段越来越多,其中就包括我们都反感的垃圾邮件,QQ对于我们来说并不陌生,相信国内大部分的网民都在使用QQ,如果我们开通了QQ邮件的功能,经常会收到一些垃圾邮件。网上...
  • dyllove98
  • dyllove98
  • 2013-08-03 21:30:10
  • 2587

C#QQ登录,获取好友列表群列表,QQ消息群发源码

  • 2014年10月05日 01:09
  • 1.35MB
  • 下载

C# 实现自动获取QQ群成员

  • 2014年08月12日 23:50
  • 183KB
  • 下载

webQQ获得群列表、好友列表

本文来源于:http://hi.baidu.com/5457090/item/9746ca53536bf2968d12ed56 转载请注明出处 ...
  • wluomu
  • wluomu
  • 2012-11-29 22:42:26
  • 1633

c#打造QQ群群发器 简单版

对于QQ群群发器来说,大家在网上见到的有很多,众多之众,但是总是不止有一个方法可以实现,我的上级告诉我,方法总比困难多,于是我在三天的时间里用c#写了一个QQ群群发器,思路简单,逻辑简单且不易理解, ...
  • qq_37499645
  • qq_37499645
  • 2017-07-30 12:39:42
  • 866

C#实现QQ群成员列表导出及邮件群发之模拟QQ登陆

前言 本文的重要部分: 1、抓包获取QQ空间或者邮箱登陆地址,分析参数,用户名,密码,验证码,gtk,随即数。 2、获取每次登陆需要的验证码 3、用户名,密码,验证码加密得到登...
  • tekucong
  • tekucong
  • 2013-11-22 13:31:46
  • 1371

9 行 javascript 代码获取 QQ 群成员

转自:http://justjavac.com/javascript/2013/10/15/9-hang-daima-huoqu-qq-qun-chengyuan.html 使用方式 先进...
  • wide288
  • wide288
  • 2013-10-15 14:27:53
  • 1418

C# 实现IAccessible学习(四)读取QQ聊天窗口记录

代码类:using QqHelper; using System; using System.Runtime.InteropServices;namespace QqRead { //参考网址...
  • xundh
  • xundh
  • 2016-06-11 16:39:11
  • 4768

C# QQ机器人(自动应答) (基于WebQQ)

QQ机器人,作用 不大,意义却不小 。此次采用轻处理方式实现,不设计QQ协议以及什么登陆加密方式等等问题研究。从web版QQ切入。整个设计思路:用c#的webbrowser控件加载web QQ,以we...
  • cctvcqupt
  • cctvcqupt
  • 2015-09-01 23:45:58
  • 3161
收藏助手
不良信息举报
您举报文章:C# 获取QQ群数据的实现
举报原因:
原因补充:

(最多只允许输入30个字)