欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-11-12 15:53:58
依然使用ie9的捕获参数,做了一个12306的登录功能。参照了网上童鞋们的做法。 其他都和前面几篇读取余票、票价一样,不过登录要用到证书的问题,这个参考了一个网上的例子。...

依然使用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();
    }
  }

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