程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 編程樂趣:C#實現12306自動登錄(2013年11月27)

編程樂趣:C#實現12306自動登錄(2013年11月27)

編輯:關於C語言

依然使用IE9的捕獲參數,做了一個12306的登錄功能。參照了網上童鞋們的做法。
其他都和前面幾篇讀取余票、票價一樣,不過登錄要用到證書的問題,這個參考了一個網上的例子。
不過12306會隨時變化,下面的登錄不一定一直都能成功。如果12306有變化,大家可以根據變化對代碼做修改。總之使用的方法不變,就是捕獲參數和url,然後自己補充參數。
效果如下:
SouthEast
項目名稱:Test12306AutoLogin;
環境:.net 4.0,Visual studio 2010;
項目圖:
SouthEast
直接貼代碼了。
核心代碼如下,
信任證書代碼:

 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();
        }
    }
代碼下載


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved