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

作者:yangyoushan 时间:2023-11-07 13:20:27 

依然使用IE9的捕获参数,做了一个12306的登录功能。参照了网上童鞋们的做法。
其他都和前面几篇读取余票、票价一样,不过登录要用到证书的问题,这个参考了一个网上的例子。
不过12306会随时变化,下面的登录不一定一直都能成功。如果12306有变化,大家可以根据变化对代码做修改。总之使用的方法不变,就是捕获参数和url,然后自己补充参数。
效果如下:

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

项目名称:Test12306AutoLogin;
环境:.net 4.0,Visual studio 2010;
项目图:

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

核心代码如下,信任证书代码:


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();
   }
 }
标签:C#,登录
0
投稿

猜你喜欢

  • Spring AOP实现复杂的日志记录操作(自定义注解)

    2023-01-24 15:21:50
  • 详解用Eclipse如何创建Web项目

    2023-11-11 05:41:01
  • java递归实现拼装多个api的结果操作方法

    2023-11-24 23:44:35
  • MyBatis3源码解析之如何获取数据源详解

    2023-12-06 02:23:08
  • Java多线程yield心得分享

    2023-11-29 05:58:15
  • Android Studio配置(Android Studio4.1为例)

    2022-04-18 04:19:18
  • IDEA自定义常用代码块及自定义快捷摸板

    2022-01-13 18:54:22
  • Mybatis配置文件之动态SQL配置备忘录

    2023-11-21 00:13:02
  • 深入解析C#设计模式中对桥接模式的具体运用

    2023-11-08 21:53:06
  • android之listview悬浮topBar效果

    2022-12-24 23:29:58
  • 浅谈C#中简单的异常引发与处理操作

    2022-03-10 04:54:49
  • java中sleep方法和wait方法的五个区别

    2023-08-27 18:37:23
  • Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法

    2023-11-19 00:24:05
  • java实现PPT转化为PDF

    2021-06-17 05:02:24
  • Android中的webview支持页面中的文件上传实例代码

    2023-12-27 06:44:17
  • Java实现树形List与扁平List互转的示例代码

    2023-03-15 00:18:23
  • Java利用Strategy模式实现堆排序

    2022-07-16 08:01:04
  • Java中七种排序算法总结分析

    2023-03-27 19:41:44
  • Android startService的使用与Service生命周期案例详解

    2021-07-14 01:51:24
  • C#采用FileSystemWatcher实现监视磁盘文件变更的方法

    2023-12-10 02:52:49
  • asp之家 软件编程 m.aspxhome.com