c#模拟网页实现12306登陆、自动刷票、自动抢票完全篇

article/2025/8/19 20:24:52

 这一篇文章,我将从头到尾教大家使用c#模拟网页面登陆12306网站,自动刷票,选择订票人,到最后一步提交订单。研究过HTTP协议的童鞋们都知道,我们在访问网站时,是有两种方式的,POST和GET方式,HTTP协议是TCP/IP的一部分,有兴趣的可以使用Socket通讯可以模拟出HTTP的访问机制。我们再说POST和GET方式,在访问一个页面时,浏览器会提交一个本地cookie提交到网站服务器,cookie的作用可以是保存我们登陆网站成功后取得的一串钥匙,也可以是其他的一些重要的信息。这是至关重要的一步。让我们步入正题。

我们来了解12306的登陆方式,我们使用http跟踪发现他的登陆的地址

https://kyfw.12306.cn/otn/login/loginAysnSuggest

 

在登陆过过程中提交了一个表单数据,包括loginserDTO.user_name、userDTO.password、randCode。我第一次看见时都有点悲催了,这么一个大的网站,密码传输竟然是明文的..

第一个参数是我们的用户名、第二是密码、第三个是校验码。

接下来我们要做的就是获取登陆验证码了。我们看到验证码的地址是

 

这是一个图片的地址,我们将这个图片地址指向我们的picturebox控件的Image路径。最终的登陆界面是这样的

新建一个HttpWebRequestExtension.cs 类,加入我们核心代码,包括提交订单数据,获取网页内容,获取校验码图片。

/// <summary> /// 模拟网页操作,提交、获取订单页面数据 /// </summary> public class HttpWebRequestExtension { private static string contentType = "application/x-www-form-urlencoded"; private static string accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-silverlight-2-b1, */*"; private static string userAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; Zune 4.7; BOIE9;ZHCN)"; private static string referer = "https://kyfw.12306.cn/"; /// <summary> /// 提交订单数据 /// </summary> /// <param name="url"></param> /// <param name="cookie"></param> /// <param name="param"></param> /// <returns></returns> public static string PostWebContent(string url, CookieContainer cookie, string param) { byte[] bs = Encoding.ASCII.GetBytes(param); var httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); httpWebRequest.CookieContainer = cookie; httpWebRequest.ContentType = contentType; httpWebRequest.Accept = accept; httpWebRequest.UserAgent = userAgent; httpWebRequest.Method = "POST"; httpWebRequest.ContentLength = bs.Length; using (Stream reqStream = httpWebRequest.GetRequestStream()) { reqStream.Write(bs, 0, bs.Length); } var httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); Stream responseStream = httpWebResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8); string html = streamReader.ReadToEnd(); streamReader.Close(); responseStream.Close(); httpWebRequest.Abort(); httpWebResponse.Close(); return html; } /// <summary> /// 获取页面数据 /// </summary> /// <param name="url"></param> /// <param name="cookie"></param> /// <returns></returns> public static string GetWebContent(string url, CookieContainer cookie) { var httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); httpWebRequest.CookieContainer = cookie; httpWebRequest.ContentType = contentType; httpWebRequest.Referer = referer; httpWebRequest.Accept = accept; httpWebRequest.UserAgent = userAgent; httpWebRequest.Method = "GET"; httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue; var httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); Stream responseStream = httpWebResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8); string html = streamReader.ReadToEnd(); streamReader.Close(); responseStream.Close(); httpWebRequest.Abort(); httpWebResponse.Close(); return html; } /// <summary> /// 获取网页验证码图片 /// </summary> /// <param name="url"></param> /// <param name="cookie"></param> /// <returns></returns> public static object GetWebImage(string url, CookieContainer cookie) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Referer = referer; request.UserAgent = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36"; request.Accept = "image/webp,*/*;q=0.8"; request.CookieContainer = cookie; request.ContentType = contentType; request.KeepAlive = true; request.UseDefaultCredentials = true; // request.Proxy = null; return request.GetResponse().GetResponseStream(); } }

然后我们就可以模拟登陆12306了。

var loginRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.AsynSugguestUrl, cookieContainer, "loginUserDTO.user_name=" + userLogin.UserName + "&&userDTO.password=" + userLogin.Password + "&&randCode=" + userLogin.VerifyCode );

 

 

登陆的结果是以JSON数据格式返回的。如果你看到有 loginCheck\":\"Y\",那么恭喜,你已经登陆上网站了。

如果失败了也无妨,返回的结果可以看到登陆失败的原因,message:[“..”], ...表示返回的错误原因,这里就不一一列出了。

 

注意:登陆成功后保存cookie的状态,前面强调过这是最重要的一个环节。

 

然后获取车站信息。车站信息保存在一个JS里面,我们需要解码JS。

https://kyfw.12306.cn/otn/resources/js/framework/station_name.js

 

大家使用浏览器打开看看,里面是不是一个定义好的以|分隔的车站信息,我们只需要提取出车站名称和车站编码。以下是我的解码方式。

var s = station.Split('=')[1].Replace("'", "").Replace(";", "").Split('|'); for (int i = 0; i < s.Length; i++) { if (i % 5 == 0) { if ((i + 1) < s.Length && (i + 4) < s.Length) { string statename = s[i + 1]; string code = s[i + 2]; cacheDic.Add(statename, code); cmbstartStation.Items.Add(statename); cmbendStation.Items.Add(statename); } } }

再进一下获取购票人信息,我们的联系人的URL是 https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs,这是一个JSON数据。

 

 

JSON数据里面包含有所有联系人的信息内容,包括电话、身份证号、出生年月、是否学生、性别等。有了这些基础数据我们就可以刷票、购票了。让我们先看看剩余的票数吧

https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={0}&leftTicketDTO.from_station={1}&leftTicketDTO.to_station={2}&purpose_codes=ADULT

 

URL里面传递的数据有始发站、终点站、出发日期等信息。 我们使用Get 方式获取余票信息

var url = string.Format(TrainUrlConstant.TrainleftTicketInfo, startTime, from, to); var trainleftTicketInfoRes = HttpWebRequestExtension.GetWebContent(url, cookieContainer);

 

 

返回的JSON数据里面包含有车票的标志位,也就是上图的secretStr,还有出发时间、软卧数、硬卧数、软座、硬座数等。

有了这些数据 我们就可以选择自动刷票了。

 

 

 

接下来选定好坐席,车次开始抢票。

选中车次后 确认提交我们选中的车次信息,我们看一下他需要传的参数信息

var param = "secretStr=" + selectedTrainView.SrcetStr + "&train_date=" + selectedTrainView.Time + "&back_train_date=" + selectedTrainView.TotalTime + "&tour_flag=dc&purpose_codes=ADULT&query_from_station_name=" + selectedTrainView.From + "&query_to_station_name=" + selectedTrainView.To + ""; var confirmParmRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.SubmitOrderPredicateUrl, cookieContainer, param);

 

12306提交订单使用的是一个订单一个随机的token信息,那么在这之前我们就必须先要获取Token信息了

 

那么这个表单里面的token、key_check_ischange、leftTicketStr、train_location从哪里来呢?这就到了考验耐心的时候了,经过仔细的查找发现,原来这些信息是隐藏在网页的JS里面。页面地址是 https://kyfw.12306.cn/otn/confirmPassenger/initDc 不仔细看还真看不出来啊。

  

var submitPassagerRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.SubmitOrderInitialUrl, cookieContainer, "_json_att="); 

 

 

 

 

另外两个参数passengerTicketStr、oldPassengerStr 是我们选中购票人,仔细分析这串字符串,发现其中是有规律的,每一个购票人是以_分隔的。逗号前第一个数据代表的是座席号,逗号的第四个数据是联系人,记住需要用URL编码格式,第6个是身份证号,第7个是手机号。

然后再获取提交订单前的校验码 https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=passenger&rand=randp

pbxOrderCode.Image = Image.FromStream((Stream)HttpWebRequestExtension.GetWebImage(TrainUrlConstant.OrderValidateCodeUrl, cookie)); 

 

将我们上面找出来的表单信息提交到网站校验是不是有问题

param = @"cancel_flag=2&bed_level_order_num=000000000000000000000000000000&" + selectedticketcontacts + "&" + selectedoldpasswordticketcontacts + "&tour_flag=dc&randCode=" + verifyCode + "&_json_att=&REPEAT_SUBMIT_TOKEN=" + token.Trim(); var checkOrderRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.CheckOrderUrl, cookieContainer, param); var checkOrderRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.CheckOrderUrl, cookieContainer, param); if (checkOrderRes != null && checkOrderRes.IndexOf("系统忙") > 0) { return; }


正确的订单返回的结果

 

 

如果以上都没有问题的话,接下来就可以进入到真正意义的抢票过程了。我们看一下抢票的URL

https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue

param = selectedticketcontacts + "&" + selectedoldpasswordticketcontacts + "&randCode=" + verifyCode + "&purpose_codes=00&key_check_isChange=" + key_check + "&leftTicketStr=" + lefttick.Trim() + "&train_location=" + train_location + "&_json_att=&REPEAT_SUBMIT_TOKEN=" + token.Trim() + ""; var confirmOrderRes = HttpWebRequestExtension.PostWebContent(TrainUrlConstant.ConfirmOrderUrl, cookieContainer, param); var errorMsg = string.Empty; Regex.Replace(submitPassagerRes, "(errMsg).*,", new MatchEvaluator(p => { if (p.Value.IndexOf("errMsg") >= 0) { errorMsg = p.Value.Substring(0, p.Value.IndexOf(",")); errorMsg = errorMsg.Replace("errMsg", "").Replace("'", "").Replace("=", "").Replace(";", "").Replace(",", "").Replace(":", ""); } return null; }));


就差最后一步了。我们看看是不是生成订单号了。

//等待订单完成 var waitorderurl = string.Format(TrainUrlConstant.WaitOrderStateUrl, j, token); int id = 0; var ultimateRes = HttpWebRequestExtension.GetWebContent(waitorderurl, cookieContainer);


看看返回的JSON结果里面有没有orderID,当orderID大于0,表示你的票已经抢到手了。赶紧登陆网站付款去吧。


http://chatgpt.dhexx.cn/article/iAN7kLMI.shtml

相关文章

你距离家只差一个刷票脚本而已——12306刷票脚本升级版

马上就要回家了&#xff0c;票还没有。你是否用到了我去年发布的刷票脚本呢。传送门~ 我也在刷票&#xff0c;不过发现12306还是发生了一些变化&#xff0c;在使用过程中&#xff0c;发现会自动退出登录。所以对脚本做了一些改动。顺便加了一些新的功能。具体如下&#xff1a;…

搞技术的要不要学习财务知识

越是大型的集团或者企业&#xff0c;公司里面设立的部门就越多&#xff0c;也越细化&#xff0c;各部门之间既相互独立管理&#xff0c;又是相互的辅助支持&#xff0c;所以在工作中经常遇到这样的一个问题&#xff0c;就是做技术的要不要学习财务知识。这个问题其实就是把技术…

财务管理的一般常识

2019独角兽企业重金招聘Python工程师标准>>> 财务总监助理在协助财务总监做好企业理财规划与管理的时候需要首先了解以下的有关知识&#xff1a; —、财务和企业财务管理的概念 所谓“财务”&#xff0c;通俗地讲就是有关“钱财”的事务。从事一切事业都离不开钱财&…

财政系统基本知识

文章目录 一、基础数据1、单位管理修改2、部门信息 二、资产账1、卡片登记&#xff08;新增资产&#xff09;2、新增资产入账&#xff0c;也可批量入账3、卡片变动1&#xff09;普通信息变动 >>>普通信息确认2&#xff09;资产价值变动3&#xff09;资产大类变动4&…

身为企业管理者,必须了解的财务知识

财务管理工作是企业管理工作中的核心内容&#xff0c;也是企业管理工作中的难点内容&#xff0c;对于集团企业来讲更是任务艰巨而又问题频出。然而&#xff0c;信息时代的来临为解决和完善企业财务管理问题提供了新思路&#xff0c;就集团企业而言&#xff0c;财务管理信息化基…

业务:财务会计业务知识

一、引言 会计是以货币为主要计量单位&#xff0c;对企业、事业、机关、团体及其他经济组织的经济活动进行记录、计算、控制、分析、报告&#xff0c;以提供财务和管理信息的工作。会计的职能主要是反映和控制经济活动过程&#xff0c;保证会计信息的合法、真实、准确和完整&a…

软件测试分类

一、软件测试的分类 1、按开发阶段&#xff1a;单元测试、集成测试、系统测试、验收测试 2、按测试实施组织&#xff1a;α、β、第三方 3、按测试执行方式&#xff1a;静态测试、动态测试 4、按是否查看代码&#xff1a;黑盒测试、白盒测试、灰盒测试 5、按是否手工执行划分&a…

【软件工程】软件测试报告——软件测试说明书

【备注】本说明书由华中农业大学2018级计算机科学与技术专业的刘畅、刘铠铭、张清望、卢家伟四位同学共同完成。 文章目录 1 引言1.1 编写目的1.2 背景1.3 术语和缩略词1.4 参考资料 2 测试用例设计3 测试结果及分析3.1 测试环境3.2 测试用例执行3.3 结论及建议 1 引言 1.1 编…

软件测试模型有哪些?

目录 1、瀑布模型 2、V模型 3、W模型 4、H模型 5、X模型 6、前置测试模型 1、瀑布模型 瀑布模型&#xff08;Waterfall Model&#xff09;是一个软件生命周期模型&#xff0c;开发过程是通过设计一系列阶段顺序展开的&#xff0c;从系统需求分析开始直到产品发布和维护&…

1.软件测试-----软件测试的基本概念

目录 一、软件测试的基本概念 1.什么是软件测试&#xff1f; 2.软件测试和软件开发的区别&#xff1f; 3.什么是需求&#xff1f; 4.什么是BUG&#xff1f; 5.如何描述一个BUG? 6.BUG的级别&#xff1f; 7.BUG的生命周期&#xff1f; 8.软件测试的生命周期&#xff1…

软件测试菜鸟入门

更新版&#xff1a;https://weltest.blog.csdn.net/article/details/110529745 视频课程&#xff1a;https://edu.csdn.net/course/detail/23459 目录 前言... 3 软件测试流程... 3 提取测试点... 4 设计测试用例与用例评审... 4 测试类型选择... 5 测试执行与缺陷管理.…

什么是软件测试?

什么是软件测试&#xff1f; 软件测试的定义&#xff1a;在一定条件下对软件进行操作&#xff0c;发现软件的问题&#xff0c;提高软件的质量。 软件测试在开发中的有着重要地位。软件测试在各阶段的完成相应的任务&#xff0c;需求测试&#xff0c;架构测试&#xff0c;详细测…

2022最新软件测试八股文,能不能拿心仪Offer就看你背得怎样了

前言 鉴于目前测试就业越来越严峻&#xff0c;内卷也成了测试领域的代名词了。我的一个HR朋友告诉我&#xff0c;由于门槛较低&#xff0c;现在普通测试岗&#xff08;偏功能&#xff09;的投递比已经将近100&#xff0c;也就是一个岗位差不多有百分简历投进来。 所以现在还想…

想自学软件测试?一般人我还是劝你算了吧。。。

本人7年测试经验&#xff0c;在学测试之前对电脑的认知也就只限于上个网&#xff0c;玩个办公软件。这里不能跑题&#xff0c;我为啥说&#xff1a;自学软件测试&#xff0c;一般人我还是劝你算了吧&#xff1f;因为我就是那个一般人&#xff01; 软件测试基础真的很简单&…

【云服务器】免费云服务器推荐

你还在因为阿里云、腾讯云等的云服务器价格昂贵而放弃自己建站、建服务器的梦想吗&#xff1f;还在因为阿里云、腾讯云推出的免费产品不能永久使用而烦恼吗&#xff1f; 优豆云就能帮你解决。重点是&#xff0c;它提供的云服务器是免费的&#xff01;&#xff01;&#xff01;…

如何操作申请免费云服务器?

2核4G、4核8G服务器申请操作&#xff1a; 第一步&#xff1a; 注册天翼云账号通过以下链接 注册账号https://www.ctyun.cn/agent/#/invitation/20753574或者扫二维码注册 第二步&#xff1a; 注册号账号进行实名认证 个人用户可通过“身份证认证”&#xff08;扫码认证&…

云服务服务器免费使用

写作目的 最近买了个2核4G的云服务器&#xff0c;自己平时就是写个demo。感觉服务器资源浪费了&#xff0c;所以搭建了一些测试环境方便小伙伴使用。 云服务器免费使用 注意&#xff1a;仅限普通用户 ip:114.115.208.175 用户名&#xff1a;marenlvdou 密码&#xff1a;lvd…

2021各厂免费云服务器申请攻略(阿里云/腾讯云/华为云)

阿里云腾讯云华为云一直都有免费云服务器提供&#xff0c;企业用户个人用户可以申请的免费云服务器配置及免费时长都不同&#xff0c;云服务器吧来详细说下阿里云免费云服务器、腾讯云免费云服务器和华为云免费服务器申请地址、申请条件及申请攻略&#xff1a; 阿里云免费云服…

银河麒麟操作系统添加字体

麒麟操作系统之字体管理器 我们在工作或者制图时&#xff0c;经常需要一些新的字体&#xff0c;你是否时常因为不知如何添加缺失的字体而苦恼呢&#xff1f;针对这一痛点&#xff0c;我们今日便讲解应该如何给电脑添加字体~ 我们将图文相结合的方式&#xff0c;与诸君分享麒麟操…

银河麒麟v10服务器操作系统安装配置

virtualbox设置 镜像下载地址&#xff1a;https://www.kylinos.cn/scheme/server.html 网卡这里给了两张&#xff0c;一张nat模式&#xff0c;一张选择仅主机模式 系统安装 接下来就可以启动虚拟机进入系统安装步骤&#xff0c;安装过程感觉跟centos7.5基本一模一样 为了方…