做爬虫也将近有一年的时间,本人不是什么名牌大学毕业,但是对计算机的热爱无人能挡。大学学了Java语言,大四来到帝都实习找了一份Java偏数据的实习工作,工作的过程中第一次接触到了爬虫的工作,并且感觉爬虫挺有意思。从知道爬虫到某些网购平台,新闻网页等文本数据的抓取,再到登录系统做查询实时数据,再到解析验证码,以至于前两天完成12306购票系统的爬虫。完成购票系统爬虫之后自我感觉有点膨胀,但是这点小小的膨胀被我强大的内心所束缚,以至于低调的写了这篇博客,哈哈……。

这个博客写的内容是针对于当前12306版本写的,只要整理完全现在立马就能买票。2017.5.25日

在做爬虫的一年的时间里做过很多系统的注册、登录、查询等。以至于在做购票爬虫的时候不是特别困难。

事先声明,这次研究爬虫购票,纯属学习,绝对不会用于商业,如果有志同道合的盆友童鞋们欢迎一起研究哈。


据新闻说,2017春节购票时历史以来最为艰难的一年,票都去哪了?据媒体报道商业黄牛使用假身份证证件10分钟钞杀1000多张票的新闻,原来如此,越来越多的黄牛加入其中,让外出打工的人们,在外的游子们感觉到买票回家难,最后不得不拿高价买黄牛手中的票回家。其实我想说使用技术的眼光去看待问题,也是可以达到四两拨千斤的效果。

再次声明,本篇博客,纯属学习,绝对不会用于商业,如果有志同道合的盆友童鞋们欢迎一起研究。

下面开始分享一下我是以怎样一个思路去做的,首先使用抓包工具先抓下购票过程的每一个链接,通过对每一步请求每一个链接都认真仔细分析后,查询余票需要实时监控请问量比较大最好别登录账号,减少不必要的麻烦,一旦发现有余票,程序调用登录程序,登录成功在调用购票程序。所以我的博客决定按照查询,登录,订票的顺序来写。

  • 1.查询余票

首先访问12306查询余票首页https://kyfw.12306.cn/otn/leftTicket/init
然后访问js页面https://kyfw.12306.cn/otn/leftTicket/log?leftTicketDTO.train_date=2017-06-20&leftTicketDTO.from_station=BJP&leftTicketDTO.to_station=ZZF&purpose_codes=ADULT访问时request.requestbody 要带上leftTicketDTO.train_date(发车日期;20xx-0x-xx);leftTicketDTO.from_station(出发站代码);leftTicketDTO.to_station(目的站代码);purpose_codes(乘客类型,ADULT成人,STUDENT学生) 这些参数。

返回结果
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"messages":[],"validateMessages":{}}

返回结果json中 “status”:true, 代表请求成功。
下面请求(查询车票链接)https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2017-06-20&leftTicketDTO.from_station=BJP&leftTicketDTO.to_station=ZZF&purpose_codes=ADULT访问时request.response 要带上leftTicketDTO.train_date(发车日期;20xx-0x-xx);leftTicketDTO.from_station(出发站代码);leftTicketDTO.to_station(目的站代码);purpose_codes(乘客类型,ADULT成人,STUDENT学生) 这些参数。
返回结果:这里只是其中一趟火车的信息。

"hBu8r%2BRJBF8wdG5sTYoxcJrR7lRev0Kb5SQzQ9mw8PFJK%2BdTid5mcXTFbrMCgHamBIw%2BxUlWJlQ8%0AWwe6sp0W8299q%2BHS1pWT8CI5My77rJp5AYbDbBdYAwCaWDKH9zbPfXZSXFOYE3lxqbVej2SYKNKT%0And7e93T4NKjGU86uKPP%2B1e0kXZfah5N%2FbBxBSOHYbTOWAj%2FN7Z6nt3WxzAc%2FDHOxWOUPIjCEXagd%0AlBZwonkBTG0y4ELRMg%3D%3D|预订|330000K5980T|K599|BTC|GZQ|BXP|ZZF|05:14|14:04|08:50|Y|Pm%2Bh1NV7CkWcA%2FWq%2BY69ecqgnHzi70S6ccm9xPpyQvEZ7igwpAyvCcmVrcM%3D|20170619|3|C1|09|22|0|0||||无|||1||11|无||||10401030|1413",hBu8r%2BRJBF8wdG5sTYoxcJrR7lRev0Kb5SQzQ9mw8PFJK%2BdTid5mcXTFbrMCgHamBIw%2BxUlWJlQ8%0AWwe6sp0W8299q%2BHS1pWT8CI5My77rJp5AYbDbBdYAwCaWDKH9zbPfXZSXFOYE3lxqbVej2SYKNKT%0And7e93T4NKjGU86uKPP%2B1e0kXZfah5N%2FbBxBSOHYbTOWAj%2FN7Z6nt3WxzAc%2FDHOxWOUPIjCEXagd%0AlBZwonkBTG0y4ELRMg%3D%3D
这串字符是火车的信息,在后面提交订单的时候就是提交这段字符。这段字符是随机生成的,过几秒就回失效。
解释一下:
330000K5980T 是列车编号
K599是车次
BTC是始发站包头
GZQ是终点站广州
BXP是北京
ZZF是郑州
05:14是发车时间
14:04到达时间
08:50是路程时间
Y是当前车次是否可购票Y是可以N是不可以
20170619 火车始发站时间
3是硬卧(1是硬座,2是软座,3是硬卧,4是软卧,O是高铁二等座,M是高铁一等座)
后面都是各种座位的票数信息

对于提到的列车站点代码,可以通过请求https://kyfw.12306.cn/otn/resources/js/framework/station_name.js链接,通过得到JS脚本中的station_names变量获取,对应的站点以@字符分隔。

  • 2.登录

请求登录页面:https://kyfw.12306.cn/otn/login/init
请求成功后会返回cookie:
Set-Cookie: BIGipServerotn=804258314.50210.0000;JSESSIONID=7F0000012E6A716B2D5261F9C944BCA36BED947150;route=6f50b51faa11b987e576cdb301e545c4
接下来的请求要带上这个cookie
下面要请求一个页面
https://kyfw.12306.cn/otn/dynamicJs/lsbmmlg
这个链接的/otn/dynamicJs/lsbmmlg部分是从上面请求到返回信息中拿到的,最后拼接成url进行请求。

<script src="/otn/dynamicJs/lsbmmlg" type="text/javascript" xml:space="preserve"></script>

紧接着是下载验证码:https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=login&rand=sjrand&0.9949197745699194

以此图为例:图片一共包含有八张图最后请求传的验证码参数是橙汁和火山对应小图片的位置的x,y的坐标。
发送请求验证验证码等参数是否正确https://kyfw.12306.cn/otn/passcodeNew/checkRandCodeAnsyn
请求参数request.requestbody = randCode=193%2C118%2C179%2C48&rand=sjrand
其中reandCode的参数是验证码传来的x,y的坐标,random=sjrand是固定的。
返回信息:

{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"result":"1","msg":"TRUE"},"messages":[],"validateMessages":{}}结果为"data":{"result":"1","msg":"TRUE"}表示正确

接下来请求登录https://kyfw.12306.cn/otn/login/loginAysnSuggest
请求参数:
request.requestbody=loginUserDTO.user_name=xxxxxxx
&userDTO.password=xxxxxxxx
&randCode=193%2C118%2C179%2C48

其中loginUserDTO.user_name=用户名
userDTO.password=密码
randCode=193%2C118%2C179%2C48登录验证码(同于上一个请求的randCode参数)

返回信息:

{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"otherMsg":"","loginCheck":"Y"},"messages":[],"validateMessages":{}}结果为"data":{"otherMsg":"","loginCheck":"Y"}表示登录成功。

登录成功之后会返回一个新的cookie

Set-Cookie: BIGipServerotn=250610186.24610.0000;JSESSIONID=7F000001921CE0E5DBE445F459464C88E7014568A2;route=9036359bb8a8a461c164a04f8f50b252

下面登录之后的每一个访问都要带上这个cookie去访问,否则提示未登录。

那么到这里登录已经完成……

  • 3.购票

购票前已经登录12306了,要请求购票的url,则必须要带上登录成功的时候返回回来的cookie,方可购票否则会提示未登录。

首先请求js校验页面https://kyfw.12306.cn/otn/leftTicket/log?leftTicketDTO.train_date=2017-06-09&leftTicketDTO.from_station=BJP&leftTicketDTO.to_station=ZKN&purpose_codes=ADULT
请求之前必须要带上登录成功后返回的cookie。
这是一个get请求,
leftTicketDTO.train_date = 2017-06-09 //乘车日期
leftTicketDTO.from_station = BJP //出发站
leftTicketDTO.to_station = ZKN //目的站
purpose_codes = ADULT//成人票
返回信息
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"messages":[],"validateMessages":{}}

接着请求,查询列车详细信息。
https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2017-06-09&leftTicketDTO.from_station=BJP&leftTicketDTO.to_station=ZKN&purpose_codes=ADULT
这个请求是query,上面那个请求是log
请求参数和cookie和上个链接一模一样。
这个返回的结果是:

{"validateMessagesShowId": "_validatorMessage","status": true,"httpstatus": 200,"data": {"result": ["DS4TNFZcmTcOMsShMIkX%2BmO%2FeUp%2FZB0AQmlkGulWYh8YiB3gNQ%2FVjE64vBIZbLEs%2FK9iRwFP6GRC%0A%2BDpD%2BmSV2VTyP%2FmnfBREPfgykoUKw0Kjdumgk2lHAF%2Bei%2Bv2EJJ2uSjRGofvH35ybyDZNNKIF%2BQV%0Aut2%2FBMQaivD%2F1gi8AjanDz37eKyoZJ4RkfbIHanUrIe57KPywaVolpJJuY2Oc5fHeNTJWzXZPJ3I%0ANwRAaqTfWaETt7GTHQ%3D%3D|预订|240000K4010O|K401|BXP|ZKN|BXP|ZKN|19:36|07:49|12:13|Y|u%2FgQ2DUlF6GUOnbbjwAb%2F%2Fo8eDAI9td%2B%2B2eVZ8ls6HiRH60t3pj9fn2vJMc%3D|20170609|3|PB|01|10|0|0||||6|||有||有|有||||10401030|1413"],"flag": "1","map": {"BXP": "北京西","ZKN": "周口"}},"messages": [],"validateMessages": {}
}

接下来请求https://kyfw.12306.cn/otn/login/checkUser链接来检测是否已经登录成功,请求的时候request.requestbody = _json_att=;请求时带上登录成功的cookie,即可!
返回结果为下面这段代码即为正确。
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"flag":true},"messages":[],"validateMessages":{}}

接下来请求https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest这个链接是检测当前账号有没有未完成的订单,如果有会提示让你完成订单的。
请求参数

secretStr=wvV3vqns6Cjss%2FAt4Nwk0enBSDwxzzHjLBIjQcmj4M%2FRrH1jYWTEN%2B790BtrFRYNnGynsY09mj%2Fu%0AFVt6hG5SmzwBIQ1Tp04MS8fDykPFhIeGQno00ShmvTdmMUalboFvKKbeow5atFi7IrDkWUHEHUKt%0ARRBJu8b0H3l8BQicXLWP7ucSStn0fs7BcvdO5khgQDaoPNcV8G7ZjP4pHShbqe8NVao%2BG%2BOw%2B9oc%0Aofg3MVljtOPBrzYH6w%3D%3D&train_date=2017-06-09&back_train_date=2017-05-25&tour_flag=dc&purpose_codes=ADULT&query_from_station_name=北京&query_to_station_name=周口&undefinedsecretStr //是前面提到的一串关于列车信息的字符
train_date  //发车时间
back_train_date  //购票时间
tour_flag  //购票类型 dc为单程
purpose_codes  //乘客类型
query_from_station_name  //出发站
query_to_station_name  //目的站
undefined

请求返回正确结果

{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":"N","messages":[],"validateMessages":{}}

请求提交购票人信息和选择购票坐票或者卧铺类型页面

https://kyfw.12306.cn/otn/confirmPassenger/initDcrequest.requestbody = _json_att=;

其中变量globalRepeatSubmitToken,key_check_isChange,leftTicket,tourFlag等信息要从返回信息中获取。

 var globalRepeatSubmitToken = 'e1839d98b0ce77e0530a8b3dfa8d88e5';'key_check_isChange':'D498961827DE21575074FFA713A8877C47ED76B176BCFE01FB3FBB01','leftTicketStr':'zjfo3ei6G7xunpcnPhELKQhguaV5nR5lPBa4fJv960jY5Z%2B2ogKTZbw3y4k%3D','tour_flag':'dc',

接下来就是下载提交火车票订单的验证码
https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=passenger&rand=randp&0.988283686302424

接着请求
https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo

cancel_flag=2&bed_level_order_num=000000000000000000000000000000&passengerTicketStr=(购票人信息)&oldPassengerStr=(购票人信息)&tour_flag=dc&randCode=&_json_att=&REPEAT_SUBMIT_TOKEN=e1839d98b0ce77e0530a8b3dfa8d88e5cancel_flag=2//固定参数
bed_level_order_num = 000000000000000000000000000000 //固定
passengerTicketStr = //购票人信息
tour_flag = dc  //上面从ticketInfoForPassengerForm中获取的参数
randCode //这里的这个参数为空
_json_att
REPEAT_SUBMIT_TOKEN //从上面ticketInfoForPassengerForm中获取的参数请求成功返回
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"ifShowPassCode":"N","canChooseBeds":"N","canChooseSeats":"N","choose_Seats":"MOP9","isCanChooseMid":"N","ifShowPassCodeTime":"1","submitStatus":true,"smokeStr":""},"messages":[],"validateMessages":{}}

接下来就是获取车票数目
https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount

介绍request.requestbody参数
train_date = Fri Jun 09 2017 00:00:00 GMT+0800 (中国标准时间)
train_no = 240000K4010O //火车编号
stationTrainCode = K401 //火车列号
seatType = 3 //座位类型 1是硬座,2是软座,3是硬卧,4是软卧,O是高铁二等座,M是高铁一等座,
fromStationTelecode = BXP  //出发站
toStationTelecode = ZKN  //目的站
leftTicket //从上面ticketInfoForPassengerForm中获取的参数
purpose_codes = 00
train_location = PB
_json_att
REPEAT_SUBMIT_TOKEN//从上面ticketInfoForPassengerForm中获取的参数返回结果
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"count":"0","ticket":"222","op_2":"false","countT":"0","op_1":"false"},"messages":[],"validateMessages":{}}结果显示硬卧还有"ticket":"222"。

到这都完成了的话,下面就是关键的部分了
接下来带着乘客信息去请求火车票了
https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue

passengerTicketStr=ticketStr&oldPassengerStr=oldPassengerSt&randCode=&purpose_codes=00&key_check_isChange=D498961827DE21575074FFA713A8877C47ED76B176BCFE01FB3FBB01&leftTicketStr=zjfo3ei6G7xunpcnPhELKQhguaV5nR5lPBa4fJv960jY5Z%252B2ogKTZbw3y4k%253D&train_location=PB&choose_seats=&seatDetailType=000&roomType=00&dwAll=N&_json_att=&REPEAT_SUBMIT_TOKEN=e1839d98b0ce77e0530a8b3dfa8d88e5request.requestbody中的字段都有
key_check_isChange
leftTicketStr
train_location = PB
choose_seats
seatDetailType = 000
roomType = 00
dwAll = N
_json_att
REPEAT_SUBMIT_TOKEN = e1839d98b0ce77e0530a8b3dfa8d88e5返回结果
{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"submitStatus":true},"messages":[],"validateMessages":{}}返回"data":{"submitStatus":true}说明请求成功,出票成功,如果为其他就是扣票失败

购票成功之后要知道取票码
https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime?random=1495703157038&tourFlag=dc&_json_att=&REPEAT_SUBMIT_TOKEN=e1839d98b0ce77e0530a8b3dfa8d88e5
请求这个js页面返回取票码

{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"queryOrderWaitTimeStatus":true,"count":0,"waitTime":-1,"requestId":6273433722868856171,"waitCount":0,"tourFlag":"dc","orderId":"EC89816430"},"messages":[],"validateMessages":{}}EC89816430就是我们在窗口取票时使用的取票码

到此为止把,下面的付款功能略微复杂,研究的不是特别深入在这里就不贴出来了。抢票都成功了,付款有半个小时呢,足够付款成功了。


购票程序基本已经结束。不难看出查询余票和登录相对简单,到后面提交订单之前各种校验,各种参数,都要弄清楚,这些东西我也是经过了摸索之后才完成的,但是把整个流程走下来之后,心里想想流程也就这样。

经过几天的努力取得了一点小小的收获,写了本篇博客分享给大家,希望你们在写购票爬虫的时候给你们一定的帮助。

如果有哪些地方写的不好,或者不连贯,欢迎各位少侠的留言。

解析爬虫12306购票系统流程相关推荐

  1. 【Java+JSP+MySql】12306购票系统(五)购买车票

    文章目录 选择出行需求 选择车票 确认购买 购买成功页面 选择出行需求 在页面中可以选择出发城市.到达城市以及出发日期. 代码存放在needs.jsp文件中. <%@ page language ...

  2. 9月3日科技联播:京东创始人刘强东卷入性侵疑云,香港地区即将加入12306购票系统...

    京东回应刘强东性侵事件指控不实,不管是商业陷阱还是板上钉钉的石锤,京东股票都将迎来新一轮危机:旅游约起来?香港地区即将加入12306购票系统,那台北还会远吗?阿里巴巴持续领跑全球区块链专利数,IBM哭 ...

  3. 【Java+JSP+MySql】12306购票系统(三)JDBC

    文章目录 配置JDBC 列车信息类 用户信息类 操作数据库 配置JDBC 在编写Java程序前需要配置JDBC环境,有很多教程,需要安装一个驱动. 可以自己找来参考,也可以看看以下链接的参考: 如何在 ...

  4. 【Java+JSP+MySql】12306购票系统(四)登录注册

    文章目录 登录 Servlet代码 html代码 注册 Servlet代码 html代码 登录 Servlet代码 Servlet代码所在文件夹位置如下截图所示 登陆的servlet代码文件命名为Lo ...

  5. JavaWeb数据交互前后台[Java+JSP+MySql+tomcat] 仿12306购票系统前台和后台(一)项目介绍以及需求分析

    目录 项目需求中要求的开发工具: 项目需求中使用到的技术: 前台功能概述 后台功能概述 前台界面设计 注册 登录 主页 游客访问主页 用户登录访问主页 ​ 增删改查乘车人 增加乘车人 乘车人主页分页查 ...

  6. 12306购票系统前端优化

    前端性能优化技术 要解决性能的问题,有很多种常用的方法,我在下面列举一下,我相信12306这个网站使用下面的这些技术会让其性能有质的飞跃. 一.前端负载均衡 通过DNS的负载均衡器(一般在路由器上根据 ...

  7. 【Java+JSP+MySql】12306购票系统(一)项目介绍

    文章目录 系统功能概述 系统界面设计 登录 注册 选择出行需求 选择车票 确认购买 个人信息 修改个人信息 取消订票 系统物理模型 表 视图 触发器 系统功能概述 用户登录 用户注册 用户按出发地.到 ...

  8. 12306购票信息爬虫

    12306购票信息爬虫 本文使用python3实现QQ邮箱爬虫和Email解析,会将设计思路和核心代码分享在此处,欢迎大家多多评论交流,感谢? 一.问题背景 二.预案探索 三.三个方案 1.直接抓包, ...

  9. 【6】爬虫介绍/准备工作/构建流程/获取数据/BeautifulSoup/Re(正则表达式)/正则提取/标签解析/保存数据到excel

    爬虫介绍/准备工作/构建流程/获取数据/BeautifulSoup/Re(正则表达式)/正则提取/标签解析/保存数据到excel 更新时间:2021.9.16 vedio:15,16,17,18,19 ...

最新文章

  1. 字节跳动一面:i++ 是线程安全的吗?
  2. ubuntu彻底卸载mysql并且重新安装
  3. 一个4体低位交叉的存储器_GD25Q16CSIG|NRAM存储器的原理及优势是什么?
  4. 带有JAX-WS和Spring的Web服务应用程序
  5. MSSQL游标的原理及示例
  6. WingIDE中文乱码问题解决方法
  7. 计算机算法设计与分析 数字三角形
  8. 在vmware server中部署linux redhat 5.4 ORACLE RAC11g +ASM
  9. debug安装包安装在别人手机上闪退?
  10. VMware 12 许可密钥
  11. 尔雅通识课题库【1】
  12. 生产线平衡算法matlab,装配生产线任务平衡问题的遗传算法MATLAB源代码
  13. LPDDR4学习笔记
  14. 不同云服务商之间域名转出转入(阿里云 转出至 腾讯云)
  15. 【贪玩巴斯】一文学会检索三要素:检索字段、检索词、检索算法检索(二)——「一文学会检索三要素:检索字段、检索词、检索算法」 2021-09-18
  16. 静态路由配置全面详解,静态路由快速入门指南
  17. iso-8859-1表示中文汉字
  18. 茅指数成分股投资收益可视化
  19. 功放、音响、耳机、播放器试音歌曲,说不定你会喜欢
  20. 百万富翁问题--安全多方计算

热门文章

  1. 幼儿园计算机课件制作评比表,幼儿园课件制作..ppt
  2. 数据结构 实验五 停车场管理
  3. xutils 使用规则以及所实现的功能
  4. 全球及中国电子级聚合物行业未来发展预测及投资前景分析报告2022-2028年
  5. 变得会说话的7种突破方法
  6. 【python文件操作之利用os筛选出想要的数据集】
  7. Mysql 常用语句实战(1)
  8. 推广运营新应用:短网址的正确使用方式
  9. Python读execl之xlrd库函数详解一:工作簿相关
  10. 控制Button按钮不可点击