使用HttpWebRequest模拟登陆阿里巴巴(alibaba、httpwebrequest、login)
前言
其实老喜欢取经,偶尔也得分享下。关于阿里巴巴国际站的登陆,过程有点复杂但是算不上难。一不小心少个东西倒也挺麻烦的。
主要是看下请求类HttpClient基本请求封装使用,AliClient模拟浏览器的操作与数据封装
这里只是简单说一下主要的类和注意点,主要步骤与注意点都写在代码注释里了。项目源码下载地址:http://git.oschina.net/GspringG/AliLogin
正文
-
主要类/方法
- 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; } } }
- 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; } } }
- 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的相关使用。
——我认识一个人,他每做一件小事都像救命稻草一样抓着。有一天我发现,豁!他抱着的已经是让我仰望的参天大树了.