本文介绍了C#实现12306自动登录的方法,主要方法是捕获参数和url并补充参数,需要的朋友可以参考下
依然使用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();
- }
- }
以上就是本文的全部内容,希望对大家的学习有所帮助。
新闻热点
疑难解答