C# 实现模拟登录功能,实现公共类分享。

前言

最近在研究模拟登录的各种方法, 主要想要实现的两个功能是:

1.点击按钮可以直接跳转并登录到某一个系统中。

2.抓取某一个系统中某一个页面中的特定数据。

为此在网上查了许多的资料,首先了解到自身对http协议基础知识的欠缺,初步了解后,明白想要实现模拟登录首先要学会抓包这一项基本的技能,关于抓包这里就不详细介绍了,向大家推荐一款软件fiddler,一款不错的抓包软件。

首先客户端向服务端请求无非两种类型get或post,所以我们要了解在登录某一个系统时post的地址,以及需要post的参数。这些都需要通过抓包来获取。

一、简单的表单提交

第一种功能跳转就是简单的表单的提交,所有系统的登录都是表单的post提交,所以只需要在html中模拟写出该系统的表单需要提交的参数并赋值,提交表单即可跳转。

      /// <summary>
        ///返回html表单
        ///action post地址,postDict键值对
        /// <summary>
        public string getPostFormHtml(HJFormModel model)
        {
            string action = model.action;
            Dictionary<string, string> postDict = model.postDict;
            StringBuilder sb = new StringBuilder();
            sb.Append("<form method=\"post\" myHttpForm\" action=\"" + action + "\">");
            sb.Append("    <div>");
            sb.Append("        <br />");
            foreach (var dic in postDict)
            {
                sb.Append("        <input type=\"hidden\" name=\"" + dic.Key + "\" value=\"" + dic.Value + "\" />");
            }
            sb.Append("        <input type=\"submit\" value=\"登录\" />");
            sb.Append("    </div>");
            sb.Append("    </form>");
            return sb.ToString();
        }
    /// <summary>
    /// Form表单生成请求参考类
    /// </summary>
    public class HJFormModel
    { /// <summary>
        /// 表单提交地址
        /// </summary>
        public string action { get; set; }
        /// <summary>
        /// 需要提交的数据参数
        /// </summary>
        public Dictionary<string, string> postDict { get; set; }
    }

上面是代码下面是请求类,就是从后台返回html,生成一个表单,提交即可,其中postDict 指需要提交的参数这里由键值对来赋值,如遇到需要输入验证码的登录那么就需要增加一条验证码连接的图片,人工识别填写(目前没有想到更好的方法)。

二、模拟登录抓取页面数据

第二种功能抓取页面的特定数据,其实就是获取某一页面所以的html,顺序一样首先要登录到系统中,下面附上公共类的代码。

        /// <summary>
        ///根据参数,返回指定内容
        /// <summary>
        public HJHttpResult GetHtml(HJHttpItem Item)
        {
            HJHttpResult res = new HJHttpResult();
            try
            {
                string htmldate;
                string html;
                CookieCollection cook = new CookieCollection();
                cook = getCook(Item.GetCookieUrl, Item.Domain, Item.CookName);
                if (!string.IsNullOrWhiteSpace(Item.postStingData))
                {
                    postCookLogin(Item.PostUrl, cook, Item.postStingData);
                }
                else
                {
                    postCookLogin(Item.PostUrl, cook, Item.postKeyData);
                }
                html = getAllHtml(Item.GetHtmlUrl, cook);
                if (!string.IsNullOrWhiteSpace(html))
                {
                    htmldate = getCutOutHtml(Item.beginString, Item.finishString, html);
                }
                else
                {
                    htmldate = "获取失败";
                }
                res.html = htmldate;
                res.CookieCoken = cook;
                return res;
            }
            catch (Exception ex)
            {
                res.html = "获取失败" + ex.Message;
                return res;
            }
        }

        /// <summary>
        /// 已登录成功根据Cookie查询其他特定HTML
        /// <summary>
        public string GetUrlHtml(string beginString, string finishString, string Url, CookieCollection curCookies)
        {
            string html;
            try
            {
                string AllHtml = getAllHtml(Url, curCookies);
                html = getCutOutHtml(beginString, finishString, AllHtml);
                return html;
            }
            catch (Exception ex)
            {
                html = "获取失败,请重新Post登录" + ex.Message;
                return html;
            }
        }
        /// <summary>
        ///截取html中特定的数据,beginString起始,finishString结束,html
        /// <summary>
        public string getCutOutHtml(string beginString, string finishString, string html)
        {
            int a = beginString.Length;
            int i = html.IndexOf(beginString) + a;
            int j = html.IndexOf(finishString);
            return html.Substring(i, j - i);
        }

        /// <summary>
        ///获取cookie
        ///url 获取地址,Domain Cook中的Domain,有哪些CookName
        /// <summary>
        public CookieCollection getCook(string Url, string Domain, string[] CookName)
        {
            CookieCollection curCookies = new CookieCollection();

            HttpWebRequest reqget = (HttpWebRequest)WebRequest.Create(Url);

            reqget.CookieContainer = new CookieContainer();
            reqget.CookieContainer.Add(curCookies);

            reqget.Method = "GET";
            HttpWebResponse respget = (HttpWebResponse)reqget.GetResponse();

            foreach (Cookie ck in respget.Cookies)
            {
                for (int i = 0; i < CookName.Length; i++)
                {
                    if (ck.Name == CookName[i])
                    {
                        Cookie cookget = new Cookie();
                        cookget.Value = ck.Value;
                        cookget.Name = ck.Name;
                        cookget.Domain = Domain;
                        curCookies.Add(cookget);
                    }
                }
            }
            string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
            HttpWebRequest request = WebRequest.Create(Url) as HttpWebRequest;
            request.Method = "GET";
            request.UserAgent = DefaultUserAgent;

            request.CookieContainer = new CookieContainer();
            request.CookieContainer.Add(curCookies);

            return curCookies;
        }

        /// <summary>
        ///post登录
        ///Url post 地址 ,postdata POST数据(字符串),curCookies COOKIE
        /// <summary>
        public void postCookLogin(string Url, CookieCollection curCookies, string postData)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(Url);
            //add cookie
            req.CookieContainer = new CookieContainer();
            req.CookieContainer.Add(curCookies);
            //set to POST
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            //prepare post data
            //string postDataStr = quoteParas(postDict);
            byte[] postBytes = Encoding.UTF8.GetBytes(postData);
            req.ContentLength = postBytes.Length;

            //send post data
            Stream postDataStream = req.GetRequestStream();
            postDataStream.Write(postBytes, 0, postBytes.Length);
            postDataStream.Close();

            //got response
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            string url = resp.ResponseUri.ToString();

            //got returned html
            StreamReader sr = new StreamReader(resp.GetResponseStream());
        }
        /// <summary>
        ///Url post 地址 ,postdata POST数据(键值对),curCookies COOKIE
        /// <summary>
        public void postCookLogin(string Url, CookieCollection curCookies, Dictionary<string, string> postData)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(Url);
            //add cookie
            req.CookieContainer = new CookieContainer();
            req.CookieContainer.Add(curCookies);
            //set to POST
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            //prepare post data
            string postDataStr = quoteParas(postData);
            byte[] postBytes = Encoding.UTF8.GetBytes(postDataStr);
            req.ContentLength = postBytes.Length;

            //send post data
            Stream postDataStream = req.GetRequestStream();
            postDataStream.Write(postBytes, 0, postBytes.Length);
            postDataStream.Close();

            //got response
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            string url = resp.ResponseUri.ToString();

            //got returned html
            StreamReader sr = new StreamReader(resp.GetResponseStream());
        }

        /// <summary>
        ///获取html页面
        ///cookCon 已登录成功的cook,Url 地址
        /// <summary>
        public string getAllHtml(string Url, CookieCollection curCookies)
        {
            CookieContainer cookCon = new CookieContainer();
            cookCon.Add(curCookies);
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(Url);
            //属性配置
            webRequest.AllowWriteStreamBuffering = true;
            webRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
            webRequest.MaximumResponseHeadersLength = -1;
            //webRequest.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*";
            webRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)";
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.Method = "GET";
            webRequest.Headers.Add("Accept-Language", "zh-cn");
            webRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
            webRequest.KeepAlive = true;
            webRequest.CookieContainer = cookCon;
            try
            {
                //获取服务器返回的资源
                using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
                {
                    using (Stream sream = webResponse.GetResponseStream())
                    {
                        StreamReader streamReader = new StreamReader(sream);
                        string str = streamReader.ReadToEnd();
                        return str;
                    }
                }
            }
            catch (WebException ex)
            {
                return "错误" + ex.Message;
            }
        }
        /// <summary>
        ///get方式获取验证码
        ///Url验证码的地址,COOKie cookCon,savePath保存地址
        /// <summary>
        public bool boolDowloadCheckImg(string Url, CookieContainer cookCon, string savePath)
        {
            bool bol = true;
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(Url);
            //属性配置
            webRequest.AllowWriteStreamBuffering = true;
            webRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
            webRequest.MaximumResponseHeadersLength = -1;
            //webRequest.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*";
            webRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)";
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.Method = "GET";
            webRequest.Headers.Add("Accept-Language", "zh-cn");
            webRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
            webRequest.KeepAlive = true;
            webRequest.CookieContainer = cookCon;
            try
            {
                //获取服务器返回的资源
                using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
                {
                    using (Stream sream = webResponse.GetResponseStream())
                    {
                        List<byte> list = new List<byte>();
                        while (true)
                        {
                            int data = sream.ReadByte();
                            if (data == -1)
                                break;
                            list.Add((byte)data);
                        }
                        File.WriteAllBytes(savePath, list.ToArray());
                    }
                }
            }
            catch (WebException ex)
            {
                bol = false;
            }
            catch (Exception ex)
            {
                bol = false;
            }
            return bol;
        }

        //quote the input dict values
        //note: the return result for first para no '&'
        /// <summary>
        ///键值对与字符流转换
        /// <summary>
        public string quoteParas(Dictionary<string, string> paras)
        {
            string quotedParas = "";
            bool isFirst = true;
            string val = "";
            foreach (string para in paras.Keys)
            {
                if (paras.TryGetValue(para, out val))
                {
                    if (isFirst)
                    {
                        isFirst = false;
                        quotedParas += para + "=" + HttpUtility.UrlPathEncode(val);
                    }
                    else
                    {
                        quotedParas += "&" + para + "=" + HttpUtility.UrlPathEncode(val);
                    }
                }
                else
                {
                    break;
                }
            }

            return quotedParas;
        }

    }
    /// <summary>
    /// Http请求参考类
    /// </summary>
    public class HJHttpItem
    {
        /// <summary>
        /// 获得Cookie的URL
        /// </summary>
        public string GetCookieUrl { get; set; }
        /// <summary>
        /// Cookie的Domain
        /// </summary>
        public string Domain { get; set; }
        /// <summary>
        /// 截取Html的起始位置
        /// </summary>
        public string beginString { get; set; }
        /// <summary>
        /// 截取Html的终止位置
        /// </summary>
        public string finishString { get; set; }
        /// <summary>
        /// Cookie的Name集合{"",""}
        /// </summary>
        public string[] CookName { get; set; }
        /// <summary>
        /// post的数据字符串格式 注:与postKeyData必须有一个不是为空的
        /// </summary>
        public string postStingData { get; set; }
        /// <summary>
        /// post的数据键值对格式 注:与postStingData必须有一个不是为空的
        /// </summary>
        public Dictionary<string, string> postKeyData { get; set; }
        /// <summary>
        /// post的地址
        /// </summary>
        public string PostUrl { get; set; }
        /// <summary>
        /// 获取Html的地址
        /// </summary>
        public string GetHtmlUrl { get; set; }
    }
    /// <summary>
    /// Http返回参数类
    /// </summary>
    public class HJHttpResult
    { /// <summary>
        /// 返回的Html数据
        /// </summary>
        public string html { get; set; }
        /// <summary>
        /// 返回的Cookie数据
        /// </summary>
        public CookieCollection CookieCoken { get; set; }
    }

大致原理为,首先获取相应登录系统的Cookie,这里我们要理解一下Cookie中SessionID的用处,SessionID由服务端向客户端发起,每次打开浏览器会更新SessionID,SessionID的目的是为了存贮post提交后登录状态的信息,如登录的用户,这个由系统而定,获得Cookie后利用这个Cookie和postdata向post地址提交,这时如果登录成功SessionID就记录下该账号的登录状态,此时利用SessionID访问该域下的其他页面就可以了,获取下来html截取下来想要的数据,同样有需要验证码的get方法获取验证码,人工识别输入post登录。

三、小结

最近在这方面做了一些小研究,遇到的问题还有很多,比如如何从后台登录成功后可以跳转到浏览器中并保持登录状态,而且我做测试的用的都是一些较为简单的系统,需要的参数并不复杂,如果哪位大神对这方面有着较深的研究,或者有这方面比较完善的系统可以分享,欢迎指出思路或其他有错误的地方,感激不尽。