当前位置: 移动技术网 > IT编程>开发语言>c# > C#实现12306自动登录的方法

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

2019年07月18日  | 移动技术网IT编程  | 我要评论

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

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网