C# 模拟登陆淘宝
本文说描述的C#模拟登录淘宝的方案,是将文章《Python爬虫实战五之模拟登录淘宝并获取所有订单》中所述的用Python实现的登录方法用C#来实现,登录成功后可以获取到用户的昵称,信用等级,购物车,已购买宝贝等等信息,理论上而言应该可以在此前提下实现自动拍下宝贝的功能。
*************20160813更新****************
相关源码在github上的链接:https://github.com/livezingy/TaoBao。目前该方案已失效,相关源码仅供参考。
*************20160813更新****************
不过严格来说,目前实现的模拟登录算不上真正意义上的成功,因为登录时所用的UA与加密密码是通过抓包工具抓取并且直接写入的。我觉得真正的模拟登录应该向登录微博那样,只要输入用户名与密码,模拟登录程序可以自动对用户名和密码进行处理并组织,然后可以直接提交相应的POST数据。不过TB的用户名与密码加密处理过于复杂,不是我等新手能轻易弄懂的。这是后话,先来Show一下我设计的简陋的登录界面,然后再来介绍模拟登录详情。
实现模拟登录淘宝的整理思路如下:
1. 手动到浏览器获取 ua 码以及加密后的密码,同一个账号只获取一次即可在任意时刻进行登录(在淘宝ua与加密算法未变更的前提下)。
我和原参考文献的作者一样用的是火狐浏览器自带的Firebug获取Ua与加密密码。在抓取数据前,需要提前在浏览器中设置一下显示持续日志,在网络选项卡的界面下登录淘宝。登录成功后,在网络选项卡中选择login.taobao.com且方法为POST的那一行并“显示请求细节”,在“参数”中即可找到ua以及TPL_password_2,复制这两个宝贝,在程序中按照该参数列表的格式组织POST数据,格式如下:
1 2 3 4 |
postStr = "ua=208UW5TcyMNYQwiAiwTR3tCf0J/QnhEcUp......"; postStr = postStr + "&TPL_username=用户名&TPL_password=&TPL_checkcode=&loginsite=0&newlogin=0&TPL_redirect_url=https%3A%2F%2Fwww.taobao.com%2F&from=tbTop&fc=default&style=default&css_style=&keyLogin=false&qrLogin=true&newMini=false&tid=&support=000001&CtrlVersion=1%2C0%2C0%2C7&loginType=3&minititle=&minipara=&umto=NaN&pstrong=&sign=&need_sign=&isIgnore=&full_redirect=&popid=&callback=&guf=¬_duplite_str=&need_user_id=&poy=&gvfdcname=10&gvfdcre=68747470733A2F2F7777772E74616F62616F2E636F6D2F&from_encoding=&sub=&"; postStr = postStr + "TPL_password_2=75e0f3461f735e8......&"; postStr = postStr + "loginASR=1&loginASRSuc=1&allp=&oslanguage=zh-CN&sr=1280*800&osVer=&naviVer=firefox%7C35"; |
2. 向登录界面发送登录请求,POST 一系列参数,包括 ua 码以及密码等等,获得响应,提取验证码图像。
目前验证下来,每一次登录都需要输入验证码。原参考文献中是弹出浏览器在浏览器中输入验证码,我实现时先获取验证码的链接,然后获取验证码显示到登录界面中,在登录界面中输入再实现登录。淘宝的验证码链接每一次请求都会出现不同的验证码图片,我曾经特别纠结这个问题:我请求验证码链接得到的图片应该是第二次请求该链接了(登录的第1步即会请求一次该验证码链接),淘宝会不会认为这个验证码并非第一次输入的验证码而导致我的这种操作无效呢?
事实证明我的担心是多余的,只要输入的是当前链接下的验证码都是可以成功登录的,其实我的再次请求也就相当于我们看不清验证码时刷新了一下而已。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/// <summary> /// 用Firefox抓取登录时的数据,获取登录时的ua和加密的密码,对于同一个账号,获取一次即可。用ua和加密后的密码进行模拟登录 /// </summary> /// <returns>bool,请求结果的状态码OK时,返回true;否则返回false,需要重试</returns> private bool loginIni() { item = new HttpItem() { URL = "https://login.taobao.com/member/login.jhtml", Method = "POST", Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", ContentType = "application/x-www-form-urlencoded", Referer = "https://login.taobao.com/member/login.jhtml", UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36", Postdata = postStr, cContainer = cookiesCon, KeepAlive = true, }; result = http.GetHtml(item); htmlStr = result.Html; if (result.StatusCode == System.Net.HttpStatusCode.OK) { if (htmlStr.Contains("请输入验证码")) { richTextBox1.Text = "此次安全验证异常,您需要输入验证码。\n"; Regex reg1 = new Regex(@"codeURL: ""(.*?)"","); urlCode = reg1.Match(htmlStr).Groups[1].Value; //获取验证码并显示 getIdenCode(); beNeedCode = true; return false; } else { richTextBox1.Text = "此次安全验证通过,正在登录。\n"; //若不需要输入验证码,理论上而言,此次即可得到Token //从返回结果中获取J_HToken的值,并通过Token获取st的值 Regex tmpReg = new Regex(@"id=""J_HToken"" value=""(.*?)"" />"); tokenStr = tmpReg.Match(htmlStr).Groups[1].Value; beNeedCode = false; if (tokenStr != "") { //成功获取Token值后,开始获取ST码 return (getSTbyToken()); } else { richTextBox1.Text = "获取请求失败,请您确认UA与加密密码。\n"; return false; } } } else { richTextBox1.Text = "获取请求失败,请您确认UA与加密密码。\n"; return false; } } /// <summary> /// 从验证码链接中获取验证码图片并显示在指定区域 /// </summary> private void getIdenCode() { item = new HttpItem() { URL = urlCode, Method = "GET", Accept = "*/*", Referer = "https://pin.aliyun.com/", ResultType = ResultType.Byte, cContainer = cookiesCon }; result = http.GetHtml(item); pictureBox1.Image = getImageFromByte(result.ResultByte); } private static Image getImageFromByte(byte[] PicBytes) { MemoryStream ms = new MemoryStream(PicBytes); ms.Position = 0; Image img = Image.FromStream(ms); ms.Close(); return img; } |
3. 用户手动输入验证码,重新加入验证码数据再次用 POST 方式发出请求,获得响应,提取 J_Htoken。
4. 利用 J_Htoken 向 alipay 发出请求,获得响应,提取 st 码。
5. 利用 st 码和用户名,重新发出登录请求,获得响应,提取重定向网址,存储 cookie。
后续可利用该cookie 向其他个人页面如订单页面发出请求,获得响应,提取订单详情以及实现宝贝购买等动作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
/// <summary> /// 获取st码以及top.location链接 /// </summary> private bool getSTbyToken() { string tmpTxtShow = richTextBox1.Text; item = new HttpItem() { URL = "https://passport.alipay.com/mini_apply_st.js?site=0&token=" + tokenStr + "&callback=stCallback6", Method = "GET", Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", ContentType = "application/x-www-form-urlencoded", Referer = "https://www.taobao.com/", UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36", cContainer = cookiesCon, KeepAlive = true, }; result = http.GetHtml(item); htmlStr = result.Html; //从返回结果中获取st的值 Regex tmpReg = new Regex(@"""st"":""(.*?)""}"); stStr = tmpReg.Match(htmlStr).Groups[1].Value; if (stStr != "") { //用得到的st值登录淘宝 item = new HttpItem() { URL = "https://login.taobao.com/member/vst.htm?st=" + stStr + "&TPL_username=bebigheart", Method = "GET", Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", ContentType = "application/x-www-form-urlencoded", Referer = "https://login.taobao.com/", UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36", cContainer = cookiesCon, KeepAlive = true, }; result = http.GetHtml(item); htmlStr = result.Html; tmpReg = new Regex(@"top.location = ""(.*?)"";"); string tmpStr = tmpReg.Match(htmlStr).Groups[1].Value; if (tmpStr != "") { richTextBox1.Text = tmpTxtShow + "ST码匹配成功,模拟登陆成功。"; return true; } else { return false; } } else { richTextBox1.Text = tmpTxtShow + "ST码匹配失败,模拟登陆失败,请重试!"; return false; } } |