[转载]c#实现QQ群成员列表导出及邮件群发之群列表及群成员获取 - 狼性法则 - 博客园

[转载]c#实现QQ群成员列表导出及邮件群发之群列表及群成员获取 – 狼性法则 – 博客园.

前言

通过前两篇的代码编写已经能正常模拟QQ登陆,拿到cookie也就是我们进行以后相关操作的金钥匙。这篇文章将通过代码的方式去获取登陆QQ账号的群列表,某群里面的群成员列表。

本文重点:

1、抓包获取QQ群列表访问地址

2、抓包获取QQ群成员列表

3、参数值计算,gtk的计算方法(网上几乎找不到的计算方法)

4、处理返回值

本文完成这一系列也基本算是完成了,到此篇为止,可正常获取群成员,当然也就是拿到了QQ邮箱,如果想进行其他操作的话,同样也可以用次方式来实现。

抓包

1、获取QQ群列表

首先我们用登陆成功的QQ去访问我们的群空间,群空间的头部有我的群,在此我们可以看到登陆QQ上面所有的群列表,也就是说此页面必有返回该列表的请求地址,做web开发的大体都差不多,这种东西多用Js处理,相信我们也可以抓到此地址,如下图所示。

相比而言这个地方的抓包不需要挨个去看了,这次给的JS请求地址很直观通过名字我们一眼就可以看出是群列表,在抓包过程中我们会发现有一条get_group_list的地址,不用说这个就是了,查看这个js返回的数据刚好便是群列表,如下图

右侧group便是登陆QQ上所有的qq群,包含总数目等信息。

相关请求地址:

http://qun.qzone.qq.com/cgi-bin/get_group_list?uin={0}&ua=Mozilla%2F5.0%20(Windows%20NT%206.1%3B
%20WOW64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F28.0.1500.95%20Safari
%2F537.36&random={1}&g_tk={2}

参数0:账号,参数1:随即数,参数2:此次访问的gtk值

2、获取访问群空间的成员列表

访问具体群空间,在群空间右侧有群成员选项,选择以后变回返回所有的群成员,如图

在点击群成员列表的时候我们通过抓包工具可抓起返回数据的地址,这个也很明显,很直观get_group_member,一看便知是返回群成员,查看返回的数据,下面给出fiddler和谷歌浏览器返回的数据格式

请求地址:

http://qun.qzone.qq.com/cgi-bin/get_group_member?
uin={0}&groupid={2}&random={3}&g_tk={4}

参数0:账号,参数1:群号,参数2:随即数,参数3:此次访问的gtk值

代码部分

1、gtk参数的计算(此参数的计算方法几乎没有)

  通过上述抓包我们看到,数据包主体部分最后一个参数就是g_tk值,一般是一串数字。那这个值到底怎么算出来的呢?因 为我们在网页登录QQ的时候,腾讯都会通过cookies里的skey值来计算,用js来算。既然在运算的时候执行了js脚本,那么我们就可以在抓包中获 得。那g_tk是通过什么算法算出来的?其实很简单,当我们得到skey后,循环取单字符的二进制并取左值.累加之后就得到后面的g_tk值了,这听上去 很复杂,不过算法不用我们自己写,我们只需要执行在腾讯网页登录的时候所执行的那个js脚本就可以了。在这里我已经将此算法转化成C#代码:

复制代码
/// <summary>
        /// 计算gtk
        /// </summary>
        /// <returns></returns>
        public static Int32 GetGTK(List<Cookie> cookies)
        {
            int gtk = 0;
            foreach (var item in cookies)
            {
                if (item.Name == "skey")
                {
                    int hash = 5381;
                    string str = item.Value;
                    for (int i = 0, len = str.Length; i < len; ++i)
                    {
                        hash += (hash << 5) + str.ElementAt(i);
                    }
                    gtk = hash & 0x7fffffff;
                }
            }
            return gtk;
        }
复制代码

同时也给出一个遍历CookieContainer的方法:

复制代码
/// <summary>
        /// 遍历CookieContainer
        /// </summary>
        /// <param name="cc"></param>
        /// <returns></returns>
        public static List<Cookie> GetAllCookies(CookieContainer cc)
        {
            List<Cookie> lstCookies = new List<Cookie>();

            Hashtable table = (Hashtable)cc.GetType().InvokeMember("m_domainTable",
                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField |
                System.Reflection.BindingFlags.Instance, null, cc, new object[] { });

            foreach (object pathList in table.Values)
            {
                SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list",
                    System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField
                    | System.Reflection.BindingFlags.Instance, null, pathList, new object[] { });
                foreach (CookieCollection colCookies in lstCookieCol.Values)
                    foreach (Cookie c in colCookies) lstCookies.Add(c);
            }
            return lstCookies;
        }
复制代码

唯一一个重要的参数解决以后便是请求地址,返回数据了,收获果实的时候了。

2、获取群列表

下面先写两个处理返回Json字符串的方法,本文没有用第三方的处理工具,二是用.net 3.5以后出现的System.Web.Extensions.dll中提供的序列化方法实现。

复制代码
//json解析群列表
    public class QQGropJson
    {
        public int code { get; set; }
        public int defaults { get; set; }
        public QQGrouplist data { get; set; }
        public string message { get; set; }
        public int subcode { get; set; }
    }
    public class QQGroupInfo
    {
        public int count { get; set; }
        public int flag { get; set; }
        public string groupid { get; set; }
        public string groupname { get; set; }
    }
    public class QQGrouplist
    {
        public List<QQGroupInfo> group { get; set; }
        public int guid { get; set; }
        public int total { get; set; }
    }
    //以下三个类解析群成员
    public class QQMember
    {
        public string iscreator { get; set; }
        public string ismanager { get; set; }
        public string nick { get; set; }
        public string uin { get; set; }
    }
    public class QQGroup
    {
        public int code { get; set; }
        public int subcode { get; set; }
        public string message { get; set; }
        public int defaults { get; set; }
        public QQInfo data { get; set; }
        public int level { get; set; }
        public string nick { get; set; }
        public int option { get; set; }
        public int total { get; set; }
    }
    public class QQInfo
    {
        public int alpha { set; get; }
        public int bbscount { get; set; }
        public int classs { get; set; }
        public string createtime { get; set; }
        public int filecount { get; set; }
        public string fingermemo { get; set; }
        public string groupmemo { get; set; }
        public string groupname { get; set; }
        public List<QQMember> item { get; set; }
    }
复制代码

过滤返回的_callback标签:

复制代码
/// <summary>
        /// 过滤返回的标签_callback();
        /// </summary>
        /// <param name="retstr"></param>
        /// <returns></returns>
        public static string FilterReturnstring(string retstr)
        {
            string result = retstr.Substring(10, retstr.Length - 12);
            return result;
        }
复制代码

解析返回的json数据

复制代码
//解析json字符串返回群信息
        public static List<QQGroupInfo> GetGropList(string jsonstring)
        {
            var js = new JavaScriptSerializer();
            QQGropJson grouplist = new QQGropJson();
            grouplist = js.Deserialize<QQGropJson>(jsonstring);
            return grouplist.data.group;
        }
复制代码

获取群列表

复制代码
var list = HttpHelper.GetAllCookies(_cookie);
            string gtk = HttpHelper.GetGTK(list).ToString();
            ////群列表
            string grouplisturl = string.Format(@"http://qun.qzone.qq.com/cgi-bin/get_group_list?uin={0}&random={1}&g_tk={2}",usernum,rand.NextDouble(),gtk);
            string tmp = HttpHelper.GetHtml(grouplisturl, _cookie);
            List<QQGroupInfo> grouplist = HttpHelper.GetGropList(HttpHelper.FilterReturnstring(tmp));
复制代码

解析群成员列表json的方法

复制代码
/// <summary>
        /// 群成员列表
        /// </summary>
        /// <param name="jsonstring"></param>
        /// <returns></returns>
        public static List<QQMember> GetMemberList(string jsonstring)
        {
            var js = new JavaScriptSerializer();
            QQGroup group = new QQGroup();
            group = js.Deserialize<QQGroup>(jsonstring);
            return group.data.item;
        }
复制代码

以上方法grouplist便是群列表账号

获取某一群的成员列表

复制代码
////群成员
            var list = HttpHelper.GetAllCookies(_cookie);
            string gtk = HttpHelper.GetGTK(list).ToString();
            string groupnumber = this.cmbQQgroup.SelectedValue.ToString();
            string groupmemberlist = string.Format(@"http://qun.qzone.qq.com/cgi-bin/get_group_member?uin={0}&groupid={1}&random={2}&g_tk={3}", usernum, groupnumber,rand.NextDouble(),gtk);
            string tmp = HttpHelper.GetHtml(groupmemberlist, _cookie);
            grouplist = HttpHelper.GetMemberList(HttpHelper.FilterReturnstring(tmp));//成员列表
复制代码

文章到此,群成员拿到了,同时也拿到了QQ邮箱。

结语

  本文的重点在于拿着cooke这把钥匙去开门,相对比较简单,唯一一个比较难的就是gtk参数的计算方法,这个在QQ空间对日志等操作的时候是必不可少的参数。

时间仓促,代码及文章比较杂乱,有什么出错的地方欢迎指出。若资料有用,帮忙顶一下。

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏