首页 > 编程 > C# > 正文

C#实现12306自动登录的方法

2019-10-29 21:39:44
字体:
来源:转载
供稿:网友

本文介绍了C#实现12306自动登录的方法,主要方法是捕获参数和url并补充参数,需要的朋友可以参考下

依然使用IE9的捕获参数,做了一个12306的登录功能。参照了网上童鞋们的做法。

其他都和前面几篇读取余票、票价一样,不过登录要用到证书的问题,这个参考了一个网上的例子。

不过12306会随时变化,下面的登录不一定一直都能成功。如果12306有变化,大家可以根据变化对代码做修改。总之使用的方法不变,就是捕获参数和url,然后自己补充参数。

效果如下:

C#实现12306自动登录的方法

项目名称:Test12306AutoLogin;

环境:.net 4.0,Visual studio 2010;

项目图:

C#实现12306自动登录的方法

核心代码如下,

信任证书代码:

 

 
  1. public class Messenger 
  2. public Messenger() 
  3.  
  4. public void Register(string message, Action callback) 
  5. this.Register(message, callback, null); 
  6.  
  7. public void Register<T>(string message, Action<T> callback) 
  8. this.Register(message, callback, typeof(T)); 
  9.  
  10.  
  11. void Register(string message, Delegate callback, Type parameterType) 
  12. if (String.IsNullOrEmpty(message)) 
  13. throw new ArgumentException("'message' cannot be null or empty."); 
  14.  
  15. if (callback == null
  16. throw new ArgumentNullException("callback"); 
  17.  
  18. this.VerifyParameterType(message, parameterType); 
  19.  
  20. _messageToActionsMap.AddAction(message, callback.Target, callback.Method, parameterType); 
  21.  
  22. [Conditional("DEBUG")] 
  23. void VerifyParameterType(string message, Type parameterType) 
  24. Type previouslyRegisteredParameterType = null
  25. if (_messageToActionsMap.TryGetParameterType(message, out previouslyRegisteredParameterType)) 
  26. if (previouslyRegisteredParameterType != null && parameterType != null
  27. if (!previouslyRegisteredParameterType.Equals(parameterType)) 
  28. throw new InvalidOperationException(string.Format( 
  29. "The registered action's parameter type is inconsistent with the previously registered actions for message '{0}'./nExpected: {1}/nAdding: {2}"
  30. message,  
  31. previouslyRegisteredParameterType.FullName, 
  32. parameterType.FullName)); 
  33. else 
  34. // One, or both, of previouslyRegisteredParameterType or callbackParameterType are null. 
  35. if (previouslyRegisteredParameterType != parameterType) // not both null? 
  36. throw new TargetParameterCountException(string.Format( 
  37. "The registered action has a number of parameters inconsistent with the previously registered actions for message /"{0}/"./nExpected: {1}/nAdding: {2}"
  38. message, 
  39. previouslyRegisteredParameterType == null ? 0 : 1, 
  40. parameterType == null ? 0 : 1)); 
  41.  
  42. public void NotifyColleagues(string message, object parameter) 
  43. if (String.IsNullOrEmpty(message)) 
  44. throw new ArgumentException("'message' cannot be null or empty."); 
  45.  
  46.  
  47. Type registeredParameterType; 
  48. if (_messageToActionsMap.TryGetParameterType(message, out registeredParameterType)) 
  49. if (registeredParameterType == null
  50. throw new TargetParameterCountException(string.Format("Cannot pass a parameter with message '{0}'. Registered action(s) expect no parameter.", message)); 
  51.  
  52.  
  53. var actions = _messageToActionsMap.GetActions(message); 
  54. if (actions != null
  55. actions.ForEach(action => action.DynamicInvoke(parameter)); 
  56.  
  57.  
  58. public void NotifyColleagues(string message) 
  59. if (String.IsNullOrEmpty(message)) 
  60. throw new ArgumentException("'message' cannot be null or empty."); 
  61.  
  62.  
  63. Type registeredParameterType; 
  64. if (_messageToActionsMap.TryGetParameterType(message, out registeredParameterType)) 
  65. if (registeredParameterType != null
  66. throw new TargetParameterCountException(string.Format("Must pass a parameter of type {0} with this message. Registered action(s) expect it.", registeredParameterType.FullName)); 
  67.  
  68.  
  69. var actions = _messageToActionsMap.GetActions(message); 
  70. if (actions != null
  71. actions.ForEach(action => action.DynamicInvoke()); 
  72.  
  73. private class MessageToActionsMap 
  74. internal MessageToActionsMap() 
  75.  
  76.  
  77.  
  78. internal void AddAction(string message, object target, MethodInfo method, Type actionType) 
  79. if (message == null
  80. throw new ArgumentNullException("message"); 
  81.  
  82.  
  83. if (method == null
  84. throw new ArgumentNullException("method"); 
  85.  
  86.  
  87. lock (_map) 
  88. if (!_map.ContainsKey(message)) 
  89. _map[message] = new List<WeakAction>(); 
  90.  
  91.  
  92. _map[message].Add(new WeakAction(target, method, actionType)); 
  93.  
  94.  
  95. internal List<Delegate> GetActions(string message) 
  96. if (message == null
  97. throw new ArgumentNullException("message"); 
  98.  
  99.  
  100. List<Delegate> actions; 
  101. lock (_map) 
  102. if (!_map.ContainsKey(message)) 
  103. return null
  104.  
  105.  
  106. List<WeakAction> weakActions = _map[message]; 
  107. actions = new List<Delegate>(weakActions.Count); 
  108. for (int i = weakActions.Count - 1; i > -1; --i) 
  109. WeakAction weakAction = weakActions[i]; 
  110. if (weakAction == null
  111. continue
  112.  
  113.  
  114. Delegate action = weakAction.CreateAction(); 
  115. if (action != null
  116. actions.Add(action); 
  117. else 
  118. // The target object is dead, so get rid of the weak action. 
  119. weakActions.Remove(weakAction); 
  120.  
  121.  
  122. // Delete the list from the map if it is now empty. 
  123. if (weakActions.Count == 0) 
  124. _map.Remove(message); 
  125.  
  126.  
  127. // Reverse the list to ensure the callbacks are invoked in the order they were registered. 
  128. actions.Reverse(); 
  129.  
  130.  
  131. return actions; 
  132.  
  133.  
  134. internal bool TryGetParameterType(string message, out Type parameterType) 
  135. if (message == null
  136. throw new ArgumentNullException("message"); 
  137.  
  138.  
  139. parameterType = null
  140. List<WeakAction> weakActions; 
  141. lock (_map) 
  142. if (!_map.TryGetValue(message, out weakActions) || weakActions.Count == 0) 
  143. return false
  144. parameterType = weakActions[0].ParameterType; 
  145. return true
  146.  
  147.  
  148. readonly Dictionary<string, List<WeakAction>> _map = new Dictionary<string, List<WeakAction>>(); 
  149.  
  150.  
  151.  
  152. private class WeakAction 
  153.  
  154. internal WeakAction(object target, MethodInfo method, Type parameterType) 
  155. if (target == null
  156. _targetRef = null
  157. else 
  158. _targetRef = new WeakReference(target); 
  159.  
  160.  
  161. _method = method; 
  162.  
  163.  
  164. this.ParameterType = parameterType; 
  165.  
  166.  
  167. if (parameterType == null
  168. _delegateType = typeof(Action); 
  169. else 
  170. _delegateType = typeof(Action<>).MakeGenericType(parameterType); 
  171.  
  172.  
  173. internal Delegate CreateAction() 
  174. // Rehydrate into a real Action object, so that the method can be invoked. 
  175. if (_targetRef == null
  176. return Delegate.CreateDelegate(_delegateType, _method); 
  177. else 
  178. try 
  179. object target = _targetRef.Target; 
  180. if (target != null
  181. return Delegate.CreateDelegate(_delegateType, target, _method); 
  182. catch 
  183.  
  184.  
  185. return null
  186.  
  187.  
  188. internal readonly Type ParameterType; 
  189. readonly Type _delegateType; 
  190. readonly MethodInfo _method; 
  191. readonly WeakReference _targetRef; 
  192.  
  193.  
  194. readonly MessageToActionsMap _messageToActionsMap = new MessageToActionsMap(); 

登录的所有方法类:

 

 
  1. public class Login12306Manager 
  2. private static readonly Messenger s_messenger = new Messenger(); 
  3.  
  4. public static Messenger SMessenger { get { return s_messenger; } } 
  5.  
  6. public const string APPEND_MESSAGE = "append_message"
  7.  
  8. public static string afterLoginCookie; 
  9.  
  10. private static string beforLoginCookie; 
  11.  
  12. static Login12306Manager() 
  13. SetCertificatePolicy(); 
  14.  
  15. /// <summary> 
  16. /// 登 录 
  17. /// </summary> 
  18. public static string Login(string userName,string password, string randomCode) 
  19. string resultHtml = string.Empty; 
  20.  
  21. try 
  22. string loginRand= DoGetLoginRand(); 
  23.  
  24. HttpWebRequest request = (HttpWebRequest)WebRequest.Create 
  25. (@"https://dynamic.12306.cn/otsweb/loginAction.do?method=login"); 
  26.  
  27. request.Accept = @"text/html, application/xhtml+xml, */*"
  28.  
  29. request.UserAgent = @"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
  30.  
  31. request.Referer = @"https://dynamic.12306.cn/otsweb/loginAction.do?method=init"
  32.  
  33. request.ContentType = @"application/x-www-form-urlencoded"
  34.  
  35. request.Headers[HttpRequestHeader.Cookie] = beforLoginCookie; 
  36.  
  37. request.Method = "POST"
  38.  
  39. byte[] buffer = new byte[0]; 
  40. string parameter = 
  41. @"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"
  42.  
  43. parameter = string.Format(parameter, loginRand, userName, password, randomCode); 
  44.  
  45. buffer = Encoding.UTF8.GetBytes(parameter); 
  46.  
  47. request.ContentLength = buffer.Length; 
  48. using (Stream writer = request.GetRequestStream()) 
  49. writer.Write(buffer, 0, buffer.Length); 
  50.  
  51. writer.Flush(); 
  52.  
  53. using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
  54. afterLoginCookie = response.GetResponseHeader("Set-cookie"); 
  55.  
  56.  
  57. using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) 
  58. resultHtml = reader.ReadToEnd(); 
  59.  
  60.  
  61. resultHtml = ProcessLoginResult(resultHtml); 
  62. catch{ } 
  63.  
  64. return resultHtml; 
  65.  
  66. /// <summary> 
  67. /// 刷新验证码 
  68. /// </summary> 
  69. public static string RefreshCode() 
  70. string randImageUrl = string.Empty; 
  71.  
  72. try 
  73. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(@"https://dynamic.12306.cn/otsweb/passCodeNewAction.do?module=login&rand=sjrand&{0}"
  74.  
  75. new Random().Next(10000, 1000000))); 
  76.  
  77. request.Accept = @"image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5"
  78.  
  79. request.UserAgent = @"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
  80.  
  81. request.Referer = @"https://dynamic.12306.cn/otsweb/loginAction.do?method=init"
  82.  
  83. request.Method = "GET"
  84.  
  85. using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
  86. beforLoginCookie = response.GetResponseHeader("Set-cookie"); 
  87.  
  88. beforLoginCookie = Regex.Replace(beforLoginCookie, "path(?:[^,]+),?""", RegexOptions.IgnoreCase); 
  89.  
  90. using (Stream reader = response.GetResponseStream()) 
  91. string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, new Random().Next(10000, 99999) + @"loginRandCode.JPEG"); 
  92.  
  93.  
  94. using (FileStream file = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)) 
  95. reader.CopyTo(file); 
  96.  
  97. randImageUrl = path; 
  98. catch { } 
  99.  
  100. return randImageUrl; 
  101.  
  102. private static string DoGetLoginRand() 
  103. string loginRand=string.Empty; 
  104.  
  105. try 
  106. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"https://dynamic.12306.cn/otsweb/loginAction.do?method=loginAysnSuggest"); 
  107.  
  108. request.Accept = @"application/json, text/javascript, */*"
  109.  
  110. request.UserAgent = @"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
  111.  
  112. request.Referer = @"https://dynamic.12306.cn/otsweb/loginAction.do?method=init"
  113.  
  114. request.Headers[HttpRequestHeader.Cookie] = beforLoginCookie; 
  115.  
  116. request.Method = "POST"
  117.  
  118. byte[] buffer = new byte[0]; 
  119.  
  120. buffer = Encoding.UTF8.GetBytes(string.Empty); 
  121.  
  122. request.ContentLength = buffer.Length; 
  123.  
  124. using (Stream writer = request.GetRequestStream()) 
  125. writer.Write(buffer, 0, buffer.Length); 
  126.  
  127. writer.Flush(); 
  128.  
  129. using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
  130. using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) 
  131. string result = reader.ReadToEnd(); 
  132.  
  133. var loginRandContent = JsonConvert.DeserializeObject<BeforLoginRnad>(result); 
  134.  
  135. loginRand = loginRandContent.loginRand; 
  136. catch {} 
  137.  
  138. return loginRand; 
  139. /// <summary> 
  140. /// 处理登录结果 
  141. /// </summary> 
  142. /// <param name="html">登录后返回的html文本</param> 
  143. private static string ProcessLoginResult(string html) 
  144. string m_msgPattern = "message[^/"]+/"(?'message'[^/"]+)/";"
  145.  
  146. string m_isLoginPatter = "isLogin//s*=//s*(?<val>.+)/n"
  147.  
  148. string m_loginUserNamePattern = "u_name//s*=//s*['/"](?<name>.+)['/"]"
  149.  
  150. if (html.Contains("请输入正确的验证码")) 
  151. return "验证码错误"
  152. else if (html.Contains("当前访问用户过多")) 
  153. return "当前访问用户过多,请稍后再试..."
  154. else 
  155. var match0 = Regex.Match(html, m_msgPattern, RegexOptions.Compiled); 
  156.  
  157. if (match0.Success) 
  158. string text = match0.Groups["message"].Value; 
  159.  
  160. if (text.Contains("密码") || text.Contains("登录名不存在")) 
  161. return "用户名或者密码错误"
  162. else 
  163. return text; 
  164.  
  165. var match = Regex.Match(html, m_isLoginPatter, RegexOptions.Compiled); 
  166.  
  167. if (match.Success && (match.Groups["val"].Value.Trim().ToLower() == "true")) 
  168. match = Regex.Match(html, m_loginUserNamePattern, RegexOptions.Compiled); 
  169. if (match.Success) 
  170. string name = match.Groups["name"].Value; 
  171.  
  172.  
  173. return "登录成功:" + name; 
  174. else 
  175. return "登录失败,未知错误"
  176. else 
  177. return "登录失败!!!"
  178.  
  179. /// <summary> 
  180. /// Sets the cert policy. 
  181. /// </summary> 
  182. private static void SetCertificatePolicy() 
  183. ServicePointManager.ServerCertificateValidationCallback 
  184. += RemoteCertificateValidate; 
  185.  
  186.  
  187. /// <summary> 
  188. /// Remotes the certificate validate. 
  189. /// </summary> 
  190. private static bool RemoteCertificateValidate( 
  191. object sender, X509Certificate cert, 
  192. X509Chain chain, SslPolicyErrors error) 
  193. SMessenger.NotifyColleagues(APPEND_MESSAGE, "信任任何证书..."); 
  194. return true
  195.  
  196. public class BeforLoginRnad 
  197. public string loginRand { get; set; } 
  198.  
  199.  
  200. 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代码:

 

  1. <Window x:Class="Test12306AutoLogin.MainWindow" 
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4. Title="MainWindow"
  5. <StackPanel> 
  6. <Grid> 
  7. <Grid.Resources> 
  8. <Style TargetType="TextBlock"
  9. <Setter Property="FontFamily" Value="Microsoft YaHei"/> 
  10. <Setter Property="FontSize" Value="20"/> 
  11. <Setter Property="VerticalAlignment" Value="Center"/> 
  12. </Style> 
  13.  
  14.  
  15. <Style TargetType="TextBox"
  16. <Setter Property="FontSize" Value="20"/> 
  17. <Setter Property="MinWidth" Value="300"/> 
  18. <Setter Property="Height" Value="50"/> 
  19. <Setter Property="VerticalAlignment" Value="Center"/> 
  20. </Style> 
  21.  
  22.  
  23. <Style TargetType="PasswordBox"
  24. <Setter Property="FontSize" Value="20"/> 
  25. <Setter Property="MinWidth" Value="300"/> 
  26. <Setter Property="Height" Value="50"/> 
  27. <Setter Property="VerticalAlignment" Value="Center"/> 
  28. </Style> 
  29. </Grid.Resources> 
  30. <Grid.RowDefinitions> 
  31. <RowDefinition Height="auto"/> 
  32. <RowDefinition Height="auto"/> 
  33. <RowDefinition Height="auto"/> 
  34. <RowDefinition Height="auto"/> 
  35. </Grid.RowDefinitions> 
  36.  
  37.  
  38. <Grid.ColumnDefinitions> 
  39. <ColumnDefinition Width="auto"/> 
  40. <ColumnDefinition Width="auto"/> 
  41. </Grid.ColumnDefinitions> 
  42.  
  43.  
  44. <TextBlock Grid.Row="0" Grid.Column="0" Text="用户名:"/> 
  45. <TextBox Grid.Row="0" Grid.Column="1" x:Name="txtUserName"/> 
  46.  
  47.  
  48. <TextBlock Grid.Row="1" Grid.Column="0" Text="密 码:"/> 
  49. <PasswordBox Grid.Row="1" Grid.Column="1" x:Name="txtPassword"/> 
  50.  
  51.  
  52. <TextBlock Grid.Row="3" Grid.Column="0" Text="验证码"/> 
  53. <StackPanel Grid.Row="3" Grid.Column="1" Orientation="Horizontal" 
  54. VerticalAlignment="Center"
  55. <TextBox x:Name="txtRandCode" Width="150"/> 
  56. <Image x:Name="imageRandCode" Width="70"/> 
  57. <Button Content="刷新验证码" Height="30" Width="80" Click="ButtonRefreshRandCode_Click" /> 
  58. </StackPanel> 
  59. </Grid> 
  60.  
  61.  
  62. <Button Content="登 录" Width="150" Height="50" Click="ButtonLogin_Click" /> 
  63.  
  64.  
  65. <RichTextBox x:Name="rtxResultContent" MinHeight="200"/> 
  66.  
  67.  
  68. </StackPanel> 
  69. </Window> 

后台代码:

 

 
  1. public partial class MainWindow : Window 
  2. public MainWindow() 
  3. InitializeComponent(); 
  4.  
  5.  
  6. this.Loaded += new RoutedEventHandler(MainWindow_Loaded); 
  7.  
  8.  
  9. void MainWindow_Loaded(object sender, RoutedEventArgs e) 
  10. DoRefreshRandCode(); 
  11.  
  12.  
  13. private void DoRefreshRandCode() 
  14. string imageRandUrl = Login12306Manager.RefreshCode(); 
  15.  
  16.  
  17. if (File.Exists(imageRandUrl)) 
  18. ImageSource src = (ImageSource)(new ImageSourceConverter().ConvertFromString(imageRandUrl)); 
  19.  
  20.  
  21. this.imageRandCode.Source = src; 
  22.  
  23.  
  24. this.txtRandCode.Text = string.Empty; 
  25.  
  26.  
  27. /// <summary> 
  28. /// 登录 
  29. /// </summary> 
  30. /// <param name="sender"></param> 
  31. /// <param name="e"></param> 
  32. private void ButtonLogin_Click(object sender, RoutedEventArgs e) 
  33. string userName = this.txtUserName.Text; 
  34.  
  35.  
  36. string password = this.txtPassword.Password; 
  37.  
  38.  
  39. string randCode = this.txtRandCode.Text; 
  40.  
  41.  
  42. if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(randCode)) 
  43. MessageBox.Show("请填写完整信息"); 
  44.  
  45.  
  46. return
  47.  
  48. string html = Login12306Manager.Login(userName, password, randCode); 
  49.  
  50.  
  51. System.Windows.Documents.FlowDocument doc = this.rtxResultContent.Document; 
  52.  
  53.  
  54. doc.Blocks.Clear(); 
  55.  
  56.  
  57. this.rtxResultContent.AppendText(html);  
  58.  
  59.  
  60. /// <summary> 
  61. /// 刷新验证码 
  62. /// </summary> 
  63. /// <param name="sender"></param> 
  64. /// <param name="e"></param> 
  65. private void ButtonRefreshRandCode_Click(object sender, RoutedEventArgs e) 
  66. DoRefreshRandCode(); 

以上就是本文的全部内容,希望对大家的学习有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表