zoukankan      html  css  js  c++  java
  • [c#] 网络协议模拟之QQ微博分享接口应用

          QQ微博在营销领域越来越受青睐了,这里面集成了很多非常有用的接口,像是邮件分享、空间分享、QQ分享、微信分享等。这相对于传统的直接模拟协议,登录邮箱等方式进行邮件发送甚至更有效。所有这些都没什么技术难度,所以实现起来是很简单的。如果在开发过程中遇到了些困难的话,可能是多线程的把握吧!

         在这样一些营销类项目之中,绝大多数都设计了多账号切换操作,这使得整个架构控制起来异常繁琐。对于多线程功底稍差的人来说,加上UI设计的搭配,简直就是地狱般的折磨。项目实战开发最需要的就是经验的积累,平时练习的时候就得多为下一次开发做技术上的准备,否则一旦开始就会显得很吃力耗时。

        

    上图只是我一个项目里的一张截图,我们要说的功能大致就是上面图中所表现出来的。但是这里,只做一个功能实现描述,不作项目完整实现。

    步骤:

    1.基础功能的类准备

    1.处理xml的xmlHelper,2.处理Http模拟的HttpHelper 3.处理QQ登录验证密码MD5加密的QQMd5 4.其他一些Util功能实现类

    所有这些类我会稍后放在文章附件里。

    2.创建Account用户资料类[登录]

    下面的这个类我只是给各位一个例子,可以展开看一下,但是还是要自己依据自己情况具体分析。

    View Code
    public class Account
       {
           #region 属性
           /// <summary>
           /// 帐号登录的顺序号码
           /// </summary>
           public int ID { get; set; }
           /// <summary>
           /// QQ帐号
           /// </summary>
           public string Uin { get; set; }
           public List<string> Froms { get; set; }
           public string Mail { get; set; }
           /// <summary>
           /// 昵称
           /// </summary>
           public string Nick { get; set; }
           /// <summary>
           /// 我的首页
           /// </summary>
           public string MyPage { get; set; }
           /// <summary>
           /// QQ未加密的密码
           /// </summary>
           public string Password { get; set; }
           /// <summary>
           /// QQ加密密码
           /// </summary>
           public string P { get; set; }
           /// <summary>
           /// QQ微博的Cookie容器
           /// </summary>
           public CookieContainer WeiboCookieContainer { get; set; }
           /// <summary>
           /// QQ微博的Cookie字符
           /// </summary>
           public string WeiboCookieString { get; set; }
           /// <summary>
           /// QQ微博对应的Sid
           /// </summary>
           public string Sid { get; set; }
           /// <summary>
           /// 目前帐号的状态
           /// </summary>
           public Status CurrentStatus { get; set; }
           /// <summary>
           /// 帐号类型
           /// </summary>
           public AccountStyle AccountStyle { get; set; }
           /// <summary>
           /// 是否需要验证码
           /// </summary>
           public bool NeedVerify { get; set; }
           /// <summary>
           /// 验证码图片
           /// </summary>
           public Image VerifyImage { get; set; }
           /// <summary>
           /// 验证码字符串
           /// </summary>
           public string VerifyCode { get; set; }
           
           #endregion
           #region 构造函数
           public Account()
           {
               Init();
           }
           public Account(string uin, string password)
           {
               this.Uin = uin;
               this.Password = password;
               Init();
           }
           #endregion
           #region 私有函数
           private void Init()
           {
               this.WeiboCookieContainer = new CookieContainer();
               this.CurrentStatus = Status.Unlogin;
               this.AccountStyle = AccountStyle.Unknow;
           }
           #endregion
    }
    }

    上面的那些都不是关键,我们要做的第一步还是完成“判断验证码>输入验证码(如果有的话)>登录”,除了要我完成Http模拟请求之外还要从返回的结果中提取有用的信息。

     #region 登录过程
           /// <summary>
           /// 判断登录微博是否需要验证码
           /// </summary>
           /// <returns></returns>
           public bool CheckVerify_Weibo(ref string vctype)
           {
               string url = "", html;
               url = string.Format("http://check.ptlogin2.qq.com/check?uin={0}@qq.com&appid=46000101&ptlang=2052&r={1}", this.Uin,new Random().NextDouble());
               html = HttpHelper.GetHtml(url, this.WeiboCookieContainer);
               if (string.IsNullOrEmpty(html)) return false;
               string pattern = @"ptui_checkVC\('(?'need'[^']*)','(?'vctype'[^']*)','[^']*'\);";
               string need = html.Match(pattern, "need");
               vctype = html.Match(pattern, "vctype");
               if (need == "1")
               {
                   this.CurrentStatus = Status.NeedVerify;
                  this.VerifyImage= this.GetImage();
                   return true;
               }
               else
               {
                   this.CurrentStatus = Status.Unlogin;
                   this.VerifyCode = vctype;
                   return false;
               }
             
           }
           /// <summary>
           /// 获取显示验证码
           /// </summary>
           /// <returns></returns>
           public Image GetImage()
           {
             string url = string.Format("http://captcha.qq.com/getimage?aid=46000101&r=0.38706237439032276&uin={0}@qq.com", this.Uin);
               Stream stream = HttpHelper.GetStream(url, this.WeiboCookieContainer);
               Image image = Image.FromStream(stream);
               return image;
           }
           /// <summary>
           /// 登录
           /// </summary>
           /// <returns></returns>
           public string Login()
           {
               string uin,password,verifyCode;
               uin = this.Uin;
               password = this.Password;
               verifyCode = this.VerifyCode;
               string html="";
            if (string.IsNullOrEmpty(uin) || string.IsNullOrEmpty(password))
                   throw new Exception("没有添加帐号,或帐号的密码为空");
               if (string.IsNullOrEmpty(verifyCode))
                   throw new Exception("验证码为空,无法继续登录");
               this.P = QQMd5.Encrypt(uin,password,verifyCode);
               string url = string.Format("http://ptlogin2.qq.com/login?ptlang=2052&u={0}@qq.com&p={1}&verifycode={2}&low_login_enable=1&low_login_hour=720&css=http://imgcache.qq.com/ptcss/b4/wb/46000101/login1.css&aid=46000101&mibao_css=m_weibo&u1=http%3A%2F%2Ft.qq.com&ptredirect=1&h=1&from_ui=1&dumy=&fp=loginerroralert&action=7-9-1381063&g=1&t=1&dummy=",
                                         uin, this.P, verifyCode);
               html = HttpHelper.GetHtml(url, this.WeiboCookieContainer);
               if (html.Contains("您输入的验证码不正确,请重新输入"))
                   throw new Exception(string.Format("验证码输入不正确"));
               else if (html.Contains("您输入的帐号或密码不正确,请重新输入"))
                   throw new Exception(string.Format("帐号或密码不正确"));
               else if (html.Contains("登录成功"))
               {
                   html = string.Format("登录成功");
                   this.CurrentStatus = Status.Login;
                 
               }
             
               return html;
             }

    由于本人不太喜欢用已经做好的轮子去用Json处理类(比如Newtonsoft.net),所以一般处理都是用的正则表达式,各位也可以自己用JsonObejct类去处理,不用跟我一样用正则这种笨方法。
    3.获取必要信息[提取微博数据]

     public string GetInfo()
           {string html="";
               try
               {
                   string url = "http://t.qq.com";
                   html = HttpHelper.GetHtml(url, this.WeiboCookieContainer);
                   string pattern = @"href=""(?'mypage'[^""]*)""><u>首页";
                   string mypage = html.Match(pattern, "mypage");
                   this.MyPage = mypage;
                   if (string.IsNullOrEmpty(mypage)) throw new Exception("获取微博话题列表失败");
                   pattern = @"boss=""btnWideSideMyNick"">(?'nick'[^<]*)</a>";
                   string nick = html.Match(pattern, "nick");
                   if (html.Contains("立即开通")) this.CurrentStatus = Status.NotRegist;
                   this.Nick = nick;
                   html = "成功获取微博话题列表";
               }
               catch(Exception e)
               {
                   html = e.Message;
               }
               return html;
           }
           public List<FriendInfo> GetQQFriendList()
           {
               string account = ""; string r = "1351620387406";
               account = this.MyPage.ToLower().Replace("http://t.qq.com/", "");
               string url = string.Format("http://api.t.qq.com/share/qqList.php?account={0}&r={1}&apiType=8&apiHost=http://api.t.qq.com&_r={1}",
                                                    account,r);
               HttpHelper.Referer = this.MyPage;
               HttpHelper.ExtendHeadData = string.Format("rf:{0}", this.MyPage);
               string html = HttpHelper.GetHtml(url, this.WeiboCookieContainer);
              
               HttpHelper.Referer = "";
               HttpHelper.ExtendHeadData = "";
               Regex regex = new Regex(@"(""sortId"":(?'sordId'[^""]+),)*""name"":""(?'name'[^""]+)"",(""groupId"":(?'groupId'[^,]+),)*(""member"":(?'member'\[[^\]]*\]))*", RegexOptions.IgnoreCase);
               MatchCollection matches = regex.Matches(html);
               List<FriendInfo> list = new List<FriendInfo>();
               for (int i = 0; i < matches.Count; i++)
               {
                   
                   string sortId = matches[i].Groups["sortId"].Value;
                   string name = matches[i].Groups["name"].Value;
                   string groupId = matches[i].Groups["groupId"].Value;
                   string member = matches[i].Groups["member"].Value;
                   Regex memberRegex = new Regex(@"""qq"":""(?'qq'[^""]*)"",""pic"":null,""nick"":""(?'nick'[^""]*)""", RegexOptions.IgnoreCase);
                   MatchCollection memberMatches = memberRegex.Matches(member);
                   for (int j = 0; j < memberMatches.Count; j++)
                   {
                       string qq = memberMatches[j].Groups["qq"].Value;
                       string nick = memberMatches[j].Groups["nick"].Value;
                       FriendInfo friendInfo = new FriendInfo();
                       friendInfo.Uin = qq;
                      friendInfo.Name = WebQQ.Converter.Unicode_js_1(name);
                     
                       friendInfo.Nick = WebQQ.Converter.Unicode_js_1(nick);
                       if (friendInfo.Name == "最近联系人") continue;
                       friendInfo.SortId = sortId;
                       friendInfo.GroupId = groupId;
                       friendInfo.QQ = Uin;
                        list.Add(friendInfo);
    
                   }
    
    
               }
               return list;
           }

    上面这一步不一定是必须的,但是没有这一步,我们后面所要实现的功能就会很困难。包括发送分享给QQ,这一步,因为要发送的QQ好友的号码不是真正的号码,而是一个系统随机生成的好友序列号的MD5加密字段。因此,我们也无法用于分享QQ给陌生人号码。

    4.分享

     #region 分享
           public string MailShare(string shareId,string toList,string subject,string reason)
           {
               string url, html;
               url = "http://api.t.qq.com/mail/mailShare.php";
               HttpHelper.ExtendHeadData =string.Format("rf:{0}",this.MyPage);
               HttpHelper.Referer = "http://api.t.qq.com/proxy.html";
               string mail = HttpUtility.UrlEncode(Encoding.UTF8.GetBytes(this.Mail));
               string maillist = HttpUtility.UrlEncode(Encoding.UTF8.GetBytes(toList));
                subject = HttpUtility.UrlEncode(Encoding.UTF8.GetBytes(subject));
                reason = HttpUtility.UrlEncode(Encoding.UTF8.GetBytes(reason));
               string postString = string.Format("mailAddr={0}&mlist={1}&subject={2}&body={3}&reason={4}&apiType=8&apiHost=http://api.t.qq.com",
                                               mail,toList,subject,shareId,reason);
               html = HttpHelper.GetHtml(url, postString, this.WeiboCookieContainer);
               HttpHelper.Referer = "";
    
               return html;
           }
           public string ShareQZone(string shareId, string reason)
           {
               string url = "http://api.t.qq.com/share/shareQzone.php";
               HttpHelper.ExtendHeadData = string.Format("rf:{0}", this.MyPage);
               HttpHelper.Referer = "http://api.t.qq.com/proxy.html";
               reason = HttpUtility.UrlEncode(Encoding.UTF8.GetBytes(reason));
               string postString = string.Format("id={0}&reason={1}&apiType=8&apiHost=http://api.t.qq.com",shareId,reason);
              string html = HttpHelper.GetHtml(url, postString, this.WeiboCookieContainer);
               HttpHelper.Referer = "";
               return html;
           }
           public string ShareMsg(string shareId,string uins,string group)
           {
               string url = "http://api.t.qq.com/share/shareMsg.php";
               string postString = string.Format("id={0}&uins={1}&group={2}&apiType=8&apiHost=http://api.t.qq.com",
                                       shareId,uins,group);
               HttpHelper.ExtendHeadData = string.Format("rf:{0}", this.MyPage);
               HttpHelper.Referer = "http://api.t.qq.com/proxy.html";
               string html = HttpHelper.GetHtml(url, postString, this.WeiboCookieContainer);
               HttpHelper.Referer = "";
               return html;
           }
           public string Pm_Mgr(string content,string target)
           {
               string url = "http://api.t.qq.com/inbox/pm_mgr.php";
               content = HttpUtility.UrlEncode(Encoding.UTF8.GetBytes(content));
               target = HttpUtility.UrlEncode(Encoding.UTF8.GetBytes(target));
               string postString = string.Format("source=&ptid=&roomid=&content={0}&fid=&arturl=&murl=&target={1}&func=send&ef=js&pmlang=zh_CN&apiType=8&apiHost=http://api.t.qq.com",
                                      content,target);//wuwenjun20102008,niefeng101
               string html = HttpHelper.GetHtml(url,postString, this.WeiboCookieContainer);
               return html;
           }
          #endregion

    当然,给大家分享上面的分析结果不是让大家去干一些让人讨厌的事(大家都懂的),仅仅是为那些爱好Http协议模拟的提供参考的方便。如果有和我一样对这方面有共同爱好,请继续关注本人的博客
    教程每天都更新,欢迎继续关注!



    ///******************************************************
    ///本文作者:凌晨的搜索者
    ///博客地址:http://www.cnblogs.com/uu102
    ///本文属于原创,如果有您需要的内容想要转载,请保留此段签名注释,否则作者将保留追究法律责任的权利。
    ///******************************************************
  • 相关阅读:
    cocoaPod
    Swift 命名规则
    Swift 数据类型
    Xcode Version 和Bulid 区别
    升级Xcode之后VVDocumenter-Xcode不能用的解决办法
    Mac svn
    RSA 加密
    想做AI测试,需要学习哪些数学知识?
    selenium + firefox驱动版本对应。
    开机自动启动WEB服务,共享目录。
  • 原文地址:https://www.cnblogs.com/uu102/p/2749855.html
Copyright © 2011-2022 走看看