使用HttpWebRequest模拟登陆阿里巴巴(alibaba、httpwebrequest、login)

前言

  其实老喜欢取经,偶尔也得分享下。关于阿里巴巴国际站的登陆,过程有点复杂但是算不上难。一不小心少个东西倒也挺麻烦的。

  主要是看下请求类HttpClient基本请求封装使用,AliClient模拟浏览器的操作与数据封装

  这里只是简单说一下主要的类和注意点,主要步骤与注意点都写在代码注释里了。项目源码下载地址:http://git.oschina.net/GspringG/AliLogin

正文

  1. 主要类/方法

  • HttpClient请求模拟的基础类,也就那么个过程http header设置一下,然后模拟就行了.需要注意的地方在代码注释里
    using System;
    using System.Drawing;
    using System.IO;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    
    namespace Main.Http
    {
        public class HttpClient
        {
            const string Accept = "text/html, application/xhtml+xml, */*";
            public const string UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";
            const int Timeout = 15000;//超时时间,但前提是请求允许超时才行。
            const string AcceptLanguage = "Accept-Language:zh-CN";
            const string AcceptEncoding = "Accept-Encoding:gzip, deflate";
            const string Contenttype = "application/x-www-form-urlencoded";
            /// <summary>
            /// 静态构造方法
            /// </summary>
            static HttpClient()
            {
                //伪造证书,验证服务器证书回调自动验证
                ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
                //客户端系统 win7或者winxp上可能会出现 could not create ssl/tls secure channel的问题导致加载ali登陆验证码报错
                //这里必须设置
                ServicePointManager.Expect100Continue = false;//默认是true,要手动设为false 
                ServicePointManager.SecurityProtocol=SecurityProtocolType.Ssl3;
    
                ServicePointManager.DefaultConnectionLimit = 1000;
            }
    
            public static string Get(string url, CookieContainer cookie, int retryCount = 3)
            {
                return Request(url, cookie, "GET", null, retryCount);
            }
            public static string Post(string url, CookieContainer cookie, string postData, int retryCount = 3)
            {
                return Request(url, cookie, "POST", postData, retryCount);
            }
    
            public static string Post(string url, CookieContainer cookie, string postData, Action<HttpWebRequest> beginRequest, int reTry = 0)
            {
                return Request(url, cookie, "POST", postData, reTry, beginRequest);
            }
    
            private static string Request(string url, CookieContainer cookie, string method, string postData, int retryCount, Action<HttpWebRequest> beginRequest = null)
            {
                string html = string.Empty;
                for (var i = 0; i <= retryCount; i++)
                {
                    try
                    {
                        html = Request(url, cookie, method, postData, beginRequest);
                        return html;
                    }
                    catch (Exception e)
                    {
                        if (i == retryCount)
                        {
                            throw new Exception(e.ToString());
                        }
                    }
                }
                return html;
            }
    
            public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
            {   // 伪造证书,总是接受  
                return true;
            }
    
            private static string Request(string url, CookieContainer cookie, string method, string postData, Action<HttpWebRequest> beginRequestHandle = null)
            {
                var request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = method;
                request.CookieContainer = cookie;
                request.AllowAutoRedirect = true;
                request.ContentType = Contenttype;
                request.Accept = Accept;
                request.Timeout = Timeout;
                request.UserAgent = UserAgent;
                request.Headers.Add(AcceptLanguage);
                request.Headers.Add(AcceptEncoding);
    
                request.AutomaticDecompression = DecompressionMethods.GZip;
    
                if (beginRequestHandle != null)
                    beginRequestHandle(request);
    
                if (!string.IsNullOrEmpty(postData))
                {
                    byte[] byteRequest = Encoding.UTF8.GetBytes(postData);
                    request.ContentLength = byteRequest.Length;
                    var stream = request.GetRequestStream();
                    stream.Write(byteRequest, 0, byteRequest.Length);
                    stream.Close();
                }
                var httpWebResponse = (HttpWebResponse)request.GetResponse();
    
                var responseStream = httpWebResponse.GetResponseStream();
                if (responseStream == null) return string.Empty;
                if (responseStream.CanTimeout)
                {
                    responseStream.ReadTimeout = 15000;
                }
                var encoding = Encoding.GetEncoding(httpWebResponse.CharacterSet ?? "UTF8");
    
                var streamReader = new StreamReader(responseStream, encoding);
    
                string html = streamReader.ReadToEnd();
                streamReader.Close();
                responseStream.Close();
                request.Abort();
                httpWebResponse.Close();
                return html;
            }
    
            public static byte[] DownloadFile(string url, CookieContainer cookie)
            {
                var webClient = new CookieWebClient { Cookie = cookie };
                byte[] data = webClient.DownloadData(url);
                return data;
            }
            public static Image DownloadImage(string url, CookieContainer cookie)
            {
                byte[] data = DownloadFile(url, cookie);
                var ms = new MemoryStream(data);
                var image = Image.FromStream(ms);
                ms.Close();
                return image;
            }
        }
    }
    View Code
  • AliClient:相当于一个浏览器,存储着cookie、session、_csrf_token_、userName等信息。客户端发出的模拟请求都通过AliClient发出保证全部在一个会话中。(想想一个浏览器需要些什么,浏览器是怎么做的。就感觉很合理了)
    using System;
    using System.Collections.Specialized;
    using System.Net;
    using System.Web;
    using Main.Http;
    
    namespace Main.Ali
    {
        public class AliClient
        {
            const string _csrf_token_ = "_csrf_token_";
            public CookieContainer Cookie { get; set; }
            public string SessionId { get; set; }
    
            public string CsrfToken { get; set; }
            public AliLoginUser AliLoginUser { get; set; }
            public string DmtrackPageid { get; set; }
            public string UserName
            {
                get
                {
                    if (AliLoginUser == null) return null;
                    if (AliLoginUser.person_data == null) return null;
                    return AliLoginUser.person_data.login_id;
                }
            }
            public AliClient()
            {
                Cookie = new CookieContainer();
            }
            public string Get(string url)
            {
                return HttpClient.Get(AddCsrfTokenToUrl(url), this.Cookie, 3);
            }
            public string Post(string url, string postData)
            {
                return HttpClient.Post(AddCsrfTokenToUrl(url), this.Cookie, AddCsrfTokenToPostData(postData), 3);
            }
            //post请求时不用手动加了,默认都加上
            private string AddCsrfTokenToPostData(string postData)
            {
                NameValueCollection queryString = HttpUtility.ParseQueryString(postData);
                if (queryString[_csrf_token_] == null)
                {
                    queryString.Add("_csrf_token_", this.CsrfToken);
                }
                return queryString.ToString();
            }
            //Get请求时不用手动加了,默认都加上
            private string AddCsrfTokenToUrl(string url)
            {
    
                if (string.IsNullOrWhiteSpace(this.CsrfToken)) return url;
                UriBuilder ub = new UriBuilder(url);
                NameValueCollection queryString = HttpUtility.ParseQueryString(ub.Query);
                if (queryString[_csrf_token_] == null)
                {
                    queryString.Add("_csrf_token_", this.CsrfToken);
                }
                ub.Query = queryString.ToString();
                string newurl = ub.Uri.ToString();
                return newurl;
            }
    
        }
    }
    View Code
  • AliPassporter:阿里巴巴登陆核心类(具体个注意细节点都在代码内部已注释)

    登陆过程为:从上到下依次

      1.PrepareLogin:

1         /// <summary>
2         /// 登陆前先请求一下页面获取sessionId,DmtrackPageid,初始化cookie的值,像正常访问浏览器一样
3         /// </summary>
4         /// <param name="aliClient"> AliClient当需要多账号登陆时,每个账号的cookie 各种验证id等独有的东西放到各自的Client中,相当于每个独立的浏览器</param>
5         /// <param name="isSpec">针对某种特殊情况取值方法不一样,默认false</param>
6         public static void PrepareLogin(AliClient aliClient, bool isSpec = false);

      2.DoLoginStep1:

1        /// <summary>
2         ///     登录阿里巴巴
3         /// </summary>
4         /// <param name="aliClient"> AliClient当需要多账号登陆时,每个账号的cookie 各种验证id等独有的东西放到各自的Client中</param>
5         /// <param name="account">帐户名</param>
6         /// <param name="password">密码</param>
7         /// <param name="checkCode">验证码</param>
8         /// <returns>登陆结果(true/false)</returns>
9         public static bool DoLoginStep1(AliClient aliClient, string account, string password, string checkCode);

      3.DoLoginStep2:

 1         /// <summary>
 2         ///     登录处理第二步
 3         /// </summary>
 4         /// <param name="aliClient"></param>
 5         /// <param name="userId">账户</param>
 6         /// <param name="password">密码</param>
 7         /// <param name="dmtrackPageid">令牌1</param>
 8         /// <param name="st">令牌三</param>
 9         /// <returns>登陆结果</returns>
10         private static bool DoLoginStep2(AliClient aliClient, string userId, string password, string dmtrackPageid, string st);

      4.DoCheckCode:

1         /// <summary>
2         /// 获取checkcode,图片验证码,其实有时候是不需要的。可以先判断一下,不行再获取验证码
3         /// </summary>
4         /// <param name="aliClient">aliClient</param>
5         /// <returns>验证码图片,如果是web应用,直接把checkCodeUrl(img src=checkCodeUrl)写进去就行了</returns>
6         public static Image DoCheckCode(AliClient aliClient);

      5.登陆过程中还会调用GetToken、GetSt、GetCsrfToken等方法提供登录所需要的get/post参数

      6.前端调用流程:登录过程关键代码(详情参见详细代码)

           //1.初始化_aliClient,相当于打开一个浏览器,并设置一个空的cookie
           AliClient  _aliClient=new AliClient {Cookie = new CookieContainer()};
           //2.无需验证码登陆时这里替换为PrepareLogin(_aliClient);
           RefreshCheckCode();
           //3.登陆系统,异步方法防止页面假死
           var data=await AliPassporter.DoLoginAsync(_aliClient, UserName, Password, CheckCode);
           if (data)
            {
                //登陆成功,登陆后其他数据就随便抓了,这里要注意,需要手机验证码的,要在网页中先把手机验证码输入了
                //我的测试账号默认写在里面,别乱玩就行了
                //进入管理个人信息页面
                var html = _aliClient.Get("http://accounts.alibaba.com/user/organization/manage_person_profile.htm");
                MessageBox.Show("登陆成功!");
                //_aliClient.Post("");
            }
            else
            {
                MessageBox.Show("登陆失败!");
            }            

 总结

  以上就是阿里巴巴国际站登陆的全部过程,总体大同小异,很久之前写的了(建议先把注释看一遍再用)。现在拿出来分享一下,顺便复习一下HttpWebRequest的相关使用。

posted @ 2015-01-07 21:54  SpringRen  阅读(1860)  评论(2编辑  收藏  举报