C#实现12306自动登录的方法
程序员文章站
2023-12-12 08:18:58
依然使用ie9的捕获参数,做了一个12306的登录功能。参照了网上童鞋们的做法。
其他都和前面几篇读取余票、票价一样,不过登录要用到证书的问题,这个参考了一个网上的例子。...
依然使用ie9的捕获参数,做了一个12306的登录功能。参照了网上童鞋们的做法。
其他都和前面几篇读取余票、票价一样,不过登录要用到证书的问题,这个参考了一个网上的例子。
不过12306会随时变化,下面的登录不一定一直都能成功。如果12306有变化,大家可以根据变化对代码做修改。总之使用的方法不变,就是捕获参数和url,然后自己补充参数。
效果如下:
项目名称:test12306autologin;
环境:.net 4.0,visual studio 2010;
项目图:
核心代码如下,
信任证书代码:
public class messenger { public messenger() { } public void register(string message, action callback) { this.register(message, callback, null); } public void register<t>(string message, action<t> callback) { this.register(message, callback, typeof(t)); } void register(string message, delegate callback, type parametertype) { if (string.isnullorempty(message)) throw new argumentexception("'message' cannot be null or empty."); if (callback == null) throw new argumentnullexception("callback"); this.verifyparametertype(message, parametertype); _messagetoactionsmap.addaction(message, callback.target, callback.method, parametertype); } [conditional("debug")] void verifyparametertype(string message, type parametertype) { type previouslyregisteredparametertype = null; if (_messagetoactionsmap.trygetparametertype(message, out previouslyregisteredparametertype)) { if (previouslyregisteredparametertype != null && parametertype != null) { if (!previouslyregisteredparametertype.equals(parametertype)) throw new invalidoperationexception(string.format( "the registered action's parameter type is inconsistent with the previously registered actions for message '{0}'.\nexpected: {1}\nadding: {2}", message, previouslyregisteredparametertype.fullname, parametertype.fullname)); } else { // one, or both, of previouslyregisteredparametertype or callbackparametertype are null. if (previouslyregisteredparametertype != parametertype) // not both null? { throw new targetparametercountexception(string.format( "the registered action has a number of parameters inconsistent with the previously registered actions for message \"{0}\".\nexpected: {1}\nadding: {2}", message, previouslyregisteredparametertype == null ? 0 : 1, parametertype == null ? 0 : 1)); } } } } public void notifycolleagues(string message, object parameter) { if (string.isnullorempty(message)) throw new argumentexception("'message' cannot be null or empty."); type registeredparametertype; if (_messagetoactionsmap.trygetparametertype(message, out registeredparametertype)) { if (registeredparametertype == null) throw new targetparametercountexception(string.format("cannot pass a parameter with message '{0}'. registered action(s) expect no parameter.", message)); } var actions = _messagetoactionsmap.getactions(message); if (actions != null) actions.foreach(action => action.dynamicinvoke(parameter)); } public void notifycolleagues(string message) { if (string.isnullorempty(message)) throw new argumentexception("'message' cannot be null or empty."); type registeredparametertype; if (_messagetoactionsmap.trygetparametertype(message, out registeredparametertype)) { if (registeredparametertype != null) throw new targetparametercountexception(string.format("must pass a parameter of type {0} with this message. registered action(s) expect it.", registeredparametertype.fullname)); } var actions = _messagetoactionsmap.getactions(message); if (actions != null) actions.foreach(action => action.dynamicinvoke()); } private class messagetoactionsmap { internal messagetoactionsmap() { } internal void addaction(string message, object target, methodinfo method, type actiontype) { if (message == null) throw new argumentnullexception("message"); if (method == null) throw new argumentnullexception("method"); lock (_map) { if (!_map.containskey(message)) _map[message] = new list<weakaction>(); _map[message].add(new weakaction(target, method, actiontype)); } } internal list<delegate> getactions(string message) { if (message == null) throw new argumentnullexception("message"); list<delegate> actions; lock (_map) { if (!_map.containskey(message)) return null; list<weakaction> weakactions = _map[message]; actions = new list<delegate>(weakactions.count); for (int i = weakactions.count - 1; i > -1; --i) { weakaction weakaction = weakactions[i]; if (weakaction == null) continue; delegate action = weakaction.createaction(); if (action != null) { actions.add(action); } else { // the target object is dead, so get rid of the weak action. weakactions.remove(weakaction); } } // delete the list from the map if it is now empty. if (weakactions.count == 0) _map.remove(message); } // reverse the list to ensure the callbacks are invoked in the order they were registered. actions.reverse(); return actions; } internal bool trygetparametertype(string message, out type parametertype) { if (message == null) throw new argumentnullexception("message"); parametertype = null; list<weakaction> weakactions; lock (_map) { if (!_map.trygetvalue(message, out weakactions) || weakactions.count == 0) return false; } parametertype = weakactions[0].parametertype; return true; } readonly dictionary<string, list<weakaction>> _map = new dictionary<string, list<weakaction>>(); } private class weakaction { internal weakaction(object target, methodinfo method, type parametertype) { if (target == null) { _targetref = null; } else { _targetref = new weakreference(target); } _method = method; this.parametertype = parametertype; if (parametertype == null) { _delegatetype = typeof(action); } else { _delegatetype = typeof(action<>).makegenerictype(parametertype); } } internal delegate createaction() { // rehydrate into a real action object, so that the method can be invoked. if (_targetref == null) { return delegate.createdelegate(_delegatetype, _method); } else { try { object target = _targetref.target; if (target != null) return delegate.createdelegate(_delegatetype, target, _method); } catch { } } return null; } internal readonly type parametertype; readonly type _delegatetype; readonly methodinfo _method; readonly weakreference _targetref; } readonly messagetoactionsmap _messagetoactionsmap = new messagetoactionsmap(); }
登录的所有方法类:
public class login12306manager { private static readonly messenger s_messenger = new messenger(); public static messenger smessenger { get { return s_messenger; } } public const string append_message = "append_message"; public static string afterlogincookie; private static string beforlogincookie; static login12306manager() { setcertificatepolicy(); } /// <summary> /// 登 录 /// </summary> public static string login(string username,string password, string randomcode) { string resulthtml = string.empty; try { string loginrand= dogetloginrand(); httpwebrequest request = (httpwebrequest)webrequest.create (@"https://dynamic.12306.cn/otsweb/loginaction.do?method=login"); request.accept = @"text/html, application/xhtml+xml, */*"; request.useragent = @"mozilla/5.0 (compatible; msie 9.0; windows nt 6.1; trident/5.0)"; request.referer = @"https://dynamic.12306.cn/otsweb/loginaction.do?method=init"; request.contenttype = @"application/x-www-form-urlencoded"; request.headers[httprequestheader.cookie] = beforlogincookie; request.method = "post"; byte[] buffer = new byte[0]; string parameter = @"loginrand={0}&refundlogin=n&refundflag=y&isclick=&form_tk=null&loginuser.user_name={1}&nameerrorfocus=&user.password={2}&passworderrorfocus=&randcode={3}&randerrorfocus=&ndu0nzy4na%3d%3d=nzg4zdaxmgnkytzlmtrjza%3d%3d&myversion=undefined"; parameter = string.format(parameter, loginrand, username, password, randomcode); buffer = encoding.utf8.getbytes(parameter); request.contentlength = buffer.length; using (stream writer = request.getrequeststream()) { writer.write(buffer, 0, buffer.length); writer.flush(); } using (httpwebresponse response = (httpwebresponse)request.getresponse()) { afterlogincookie = response.getresponseheader("set-cookie"); using (streamreader reader = new streamreader(response.getresponsestream(), encoding.utf8)) { resulthtml = reader.readtoend(); resulthtml = processloginresult(resulthtml); } } } catch{ } return resulthtml; } /// <summary> /// 刷新验证码 /// </summary> public static string refreshcode() { string randimageurl = string.empty; try { httpwebrequest request = (httpwebrequest)webrequest.create(string.format(@"https://dynamic.12306.cn/otsweb/passcodenewaction.do?module=login&rand=sjrand&{0}", new random().next(10000, 1000000))); request.accept = @"image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5"; request.useragent = @"mozilla/5.0 (compatible; msie 9.0; windows nt 6.1; trident/5.0)"; request.referer = @"https://dynamic.12306.cn/otsweb/loginaction.do?method=init"; request.method = "get"; using (httpwebresponse response = (httpwebresponse)request.getresponse()) { beforlogincookie = response.getresponseheader("set-cookie"); beforlogincookie = regex.replace(beforlogincookie, "path(?:[^,]+),?", "", regexoptions.ignorecase); using (stream reader = response.getresponsestream()) { string path = path.combine(appdomain.currentdomain.basedirectory, new random().next(10000, 99999) + @"loginrandcode.jpeg"); using (filestream file = new filestream(path, filemode.openorcreate, fileaccess.write)) { reader.copyto(file); } randimageurl = path; } } } catch { } return randimageurl; } private static string dogetloginrand() { string loginrand=string.empty; try { httpwebrequest request = (httpwebrequest)webrequest.create(@"https://dynamic.12306.cn/otsweb/loginaction.do?method=loginaysnsuggest"); request.accept = @"application/json, text/javascript, */*"; request.useragent = @"mozilla/5.0 (compatible; msie 9.0; windows nt 6.1; trident/5.0)"; request.referer = @"https://dynamic.12306.cn/otsweb/loginaction.do?method=init"; request.headers[httprequestheader.cookie] = beforlogincookie; request.method = "post"; byte[] buffer = new byte[0]; buffer = encoding.utf8.getbytes(string.empty); request.contentlength = buffer.length; using (stream writer = request.getrequeststream()) { writer.write(buffer, 0, buffer.length); writer.flush(); } using (httpwebresponse response = (httpwebresponse)request.getresponse()) { using (streamreader reader = new streamreader(response.getresponsestream(), encoding.utf8)) { string result = reader.readtoend(); var loginrandcontent = jsonconvert.deserializeobject<beforloginrnad>(result); loginrand = loginrandcontent.loginrand; } } } catch {} return loginrand; } /// <summary> /// 处理登录结果 /// </summary> /// <param name="html">登录后返回的html文本</param> private static string processloginresult(string html) { string m_msgpattern = "message[^\"]+\"(?'message'[^\"]+)\";"; string m_isloginpatter = "islogin\\s*=\\s*(?<val>.+)\n"; string m_loginusernamepattern = "u_name\\s*=\\s*['\"](?<name>.+)['\"]"; if (html.contains("请输入正确的验证码")) { return "验证码错误"; } else if (html.contains("当前访问用户过多")) { return "当前访问用户过多,请稍后再试..."; } else { var match0 = regex.match(html, m_msgpattern, regexoptions.compiled); if (match0.success) { string text = match0.groups["message"].value; if (text.contains("密码") || text.contains("登录名不存在")) { return "用户名或者密码错误"; } else { return text; } } var match = regex.match(html, m_isloginpatter, regexoptions.compiled); if (match.success && (match.groups["val"].value.trim().tolower() == "true")) { match = regex.match(html, m_loginusernamepattern, regexoptions.compiled); if (match.success) { string name = match.groups["name"].value; return "登录成功:" + name; } else { return "登录失败,未知错误"; } } else { return "登录失败!!!"; } } } /// <summary> /// sets the cert policy. /// </summary> private static void setcertificatepolicy() { servicepointmanager.servercertificatevalidationcallback += remotecertificatevalidate; } /// <summary> /// remotes the certificate validate. /// </summary> private static bool remotecertificatevalidate( object sender, x509certificate cert, x509chain chain, sslpolicyerrors error) { smessenger.notifycolleagues(append_message, "信任任何证书..."); return true; } } public class beforloginrnad { public string loginrand { get; set; } public string randerror { get; set; } }
注意登录时,主要的正文是:
string parameter =
@"loginrand={0}&refundlogin=n&refundflag=y&isclick=&form_tk=null&loginuser.user_name={1}&nameerrorfocus=&user.password={2}&passworderrorfocus=&randcode={3}&randerrorfocus=&ndu0nzy4na%3d%3d=nzg4zdaxmgnkytzlmtrjza%3d%3d&myversion=undefined",它有三个参数,登录时的随机码,用户名,密码和验证码组成。
调用如下:
前台wpf代码:
<window x:class="test12306autologin.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" title="mainwindow"> <stackpanel> <grid> <grid.resources> <style targettype="textblock"> <setter property="fontfamily" value="microsoft yahei"/> <setter property="fontsize" value="20"/> <setter property="verticalalignment" value="center"/> </style> <style targettype="textbox"> <setter property="fontsize" value="20"/> <setter property="minwidth" value="300"/> <setter property="height" value="50"/> <setter property="verticalalignment" value="center"/> </style> <style targettype="passwordbox"> <setter property="fontsize" value="20"/> <setter property="minwidth" value="300"/> <setter property="height" value="50"/> <setter property="verticalalignment" value="center"/> </style> </grid.resources> <grid.rowdefinitions> <rowdefinition height="auto"/> <rowdefinition height="auto"/> <rowdefinition height="auto"/> <rowdefinition height="auto"/> </grid.rowdefinitions> <grid.columndefinitions> <columndefinition width="auto"/> <columndefinition width="auto"/> </grid.columndefinitions> <textblock grid.row="0" grid.column="0" text="用户名:"/> <textbox grid.row="0" grid.column="1" x:name="txtusername"/> <textblock grid.row="1" grid.column="0" text="密 码:"/> <passwordbox grid.row="1" grid.column="1" x:name="txtpassword"/> <textblock grid.row="3" grid.column="0" text="验证码"/> <stackpanel grid.row="3" grid.column="1" orientation="horizontal" verticalalignment="center"> <textbox x:name="txtrandcode" width="150"/> <image x:name="imagerandcode" width="70"/> <button content="刷新验证码" height="30" width="80" click="buttonrefreshrandcode_click" /> </stackpanel> </grid> <button content="登 录" width="150" height="50" click="buttonlogin_click" /> <richtextbox x:name="rtxresultcontent" minheight="200"/> </stackpanel> </window>
后台代码:
public partial class mainwindow : window { public mainwindow() { initializecomponent(); this.loaded += new routedeventhandler(mainwindow_loaded); } void mainwindow_loaded(object sender, routedeventargs e) { dorefreshrandcode(); } private void dorefreshrandcode() { string imagerandurl = login12306manager.refreshcode(); if (file.exists(imagerandurl)) { imagesource src = (imagesource)(new imagesourceconverter().convertfromstring(imagerandurl)); this.imagerandcode.source = src; } this.txtrandcode.text = string.empty; } /// <summary> /// 登录 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonlogin_click(object sender, routedeventargs e) { string username = this.txtusername.text; string password = this.txtpassword.password; string randcode = this.txtrandcode.text; if (string.isnullorempty(username) || string.isnullorempty(password) || string.isnullorempty(randcode)) { messagebox.show("请填写完整信息"); return; } string html = login12306manager.login(username, password, randcode); system.windows.documents.flowdocument doc = this.rtxresultcontent.document; doc.blocks.clear(); this.rtxresultcontent.appendtext(html); } /// <summary> /// 刷新验证码 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonrefreshrandcode_click(object sender, routedeventargs e) { dorefreshrandcode(); } }
以上就是本文的全部内容,希望对大家的学习有所帮助。