12306新版抢票之逻辑分析

前言

新版的12306大概是前天上线的吧,因为我前天想抢票的时候发现之前写的程序已经无法正常工作了。

登陆的时候就会报错——“非法请求”,很纳闷,莫非是12306改了逻辑?

不过经过这两天的研究,已经又搞出了新版的抢票软件,嘿嘿,感觉值得骄傲一下~好了,不嘚瑟了

下面先从登陆入手,来剖析新版添加的dynamicJs(这个名字还挺贴切,就这么叫了)

一窥新版猫腻

下面就是新版的12306登陆所传的参数

根据我上版抢票软件的经验,其中后三个参数都是新添加的,并且其中用红框框中的那个参数的key和value都是不固定的~另外两个倒是简单,也不影响登陆的成功与否。

那么这个动态变化的参数到底是怎么来的呢?这大概就是12306这版的“骄傲”了吧——dynamicJs。从12306官网分析找到这个dynamicJs:

该js文件中对于生成动态key-value的关键片段(以及后面的gc()函数)如下:

					function() {
						(function() {
							var form = document.forms[0];
							var oldSubmit;
							if (null != form && form != 'undefined'
									&& form.id == 'loginForm') {
								form.oldSubmit = form.submit;
								submitForm = function() {
									var keyVlues = gc().split(':');
									var inputObj = $('<input type="hidden" name="'
											+ keyVlues[0]
											+ '" value="'
											+ encode32(bin216(Base32.encrypt(
													keyVlues[1], keyVlues[0])))
											+ '" />');
									var myObj = $('<input type="hidden" name="myversion" value="' + window.helperVersion + '" />');
									inputObj.appendTo($(form));
									myObj.appendTo($(form));
									delete inputObj;
									delete myObj;
								}
							} else {
								submitForm = function() {
									var keyVlues = gc().split(':');
									return keyVlues[0]
											+ ",-,"
											+ encode32(bin216(Base32.encrypt(
													keyVlues[1], keyVlues[0])))
											+ ":::" + 'myversion' + ",-,"
											+ window.helperVersion;
								};
							}
						})();
					});

核心就是submitForm这个function,它会在登陆按钮click的时候触发(其实是提交表单的时候都会触发,只是这里先只关注登陆)

可以看到上面的if-else判断中,对于form是有做区分的:分成2类,一类是id为loginForm的Form(也就是登陆表单),其余的则归为另一类。

这两类处理的逻辑不同,对于loginForm,它会在页面上插入2个隐藏域来顺着表单的提交而提交。而对于另一类,则生成2组key-value并用":::"join起来。

不过这里要小小的 吐槽一下12306一下,就是不管登陆成功与否,这两个隐藏域都会被插入,我们可以做个试验来看看,下图就是我N次登陆不成功时所发生的事情:

呵呵~这不是我们的重点。还是分析那个动态的key和value是怎么来的。由于我们只关注登陆,可以将之前的js代码精简一下:

							if (null != form && form != 'undefined'
									&& form.id == 'loginForm') {
								form.oldSubmit = form.submit;
								submitForm = function() {
									var keyVlues = gc().split(':');
									var inputObj = $('<input type="hidden" name="'
											+ keyVlues[0]
											+ '" value="'
											+ encode32(bin216(Base32.encrypt(
													keyVlues[1], keyVlues[0])))
											+ '" />');
									var myObj = $('<input type="hidden" name="myversion" value="'
											+ window.helperVersion + '" />');
									inputObj.appendTo($(form));
									myObj.appendTo($(form));
									delete inputObj;
									delete myObj;
								}
							} 

其中一个参数的key是keyValues[0],而value则是用keyValue[0]和keyValue[1]经过某些加密运算得到的值,这就是我们要找的目标参数。

好了,可以看到keyValues这个数组是通过gc()这个函数的返回值split出来的,那么看看gc()是什么:

function gc() {
		var key = 'MTk0MTEw';
		var value = '';
		var cssArr = [ 'selectSeatType', 'ev_light', 'ev_light',
				'fishTimeRangePicker', 'updatesFound', 'tipScript',
				'refreshButton', 'fish_clock', 'refreshStudentButton',
				'btnMoreOptions', 'btnAutoLogin', 'fish_button',
				'defaultSafeModeTime', 'ticket-navigation-item' ];
		var csschek = false;
		if (cssArr && cssArr.length > 0) {
			for ( var i = 0; i < cssArr.length; i++) {
				if ($('.' + cssArr[i]).length > 0) {
					csschek = true;
					break;
				}
			}
		}
		if (csschek) {
			value += '0';
		} else {
			value += '1';
		}
		var idArr = [ 'btnMoreOptions', 'refreshStudentButton',
				'fishTimeRangePicker', 'helpertooltable', 'outerbox',
				'updateInfo', 'fish_clock', 'refreshStudentButton',
				'btnAutoRefresh', 'btnAutoSubmit', 'btnRefreshPassenger',
				'autoLogin', 'bnAutoRefreshStu', 'orderCountCell',
				'refreshStudentButton', 'enableAdvPanel', 'autoDelayInvoke',
				'refreshButton', 'refreshTimesBar', 'chkAllSeat' ];
		var idchek = false;
		for ( var i = 0; i < idArr.length; i++) {
			if ($('#' + idArr[i])[0]) {
				idchek = true;
				break;
			}
		}
		if (idchek) {
			value += '0';
		} else {
			value += '1';
		}
		var attrArr = [ 'helperVersion' ];
		var attrLen = attrArr ? attrArr.length : 0;
		var attrchek = false;
		for ( var p in parent) {
			if (!attrchek) {
				for ( var k = 0; k < attrLen; k++) {
					if (String(p).indexOf(attrArr[k]) > -1) {
						attrchek = true;
						break;
					}
				}
			} else
				break;
		}
		for ( var p in window) {
			if (!attrchek) {
				for ( var k = 0; k < attrLen; k++) {
					if (String(p).indexOf(attrArr[k]) > -1) {
						attrchek = true;
						break;
					}
				}
			} else
				break;
		}
		var styleArr = [ '.enter_right>.enter_enw>.enter_rtitle', '.objbox td' ];
		var stylechek = false;
		if (styleArr && styleArr.length > 0) {
			for ( var i = 0; i < styleArr.length; i++) {
				var tempStyle = $(styleArr[i]);
				if (tempStyle[0]) {
					for ( var k = 0; k < tempStyle.length > 0; k++) {
						if (tempStyle.eq(k).attr('style')) {
							stylechek = true;
							break;
						}
					}
				}
			}
		}
		if (stylechek) {
			value += '0';
		} else {
			value += '1';
		}
		var keywordArr = [ {
			key : ".enter_right",
			values : [ "亲", "抢票", "助手" ]
		}, {
			key : ".cx_form",
			values : [ "点发车", "刷票" ]
		}, {
			key : "#gridbox",
			values : [ "只选", "仅选", "checkBox", "checkbox" ]
		}, {
			key : ".enter_w",
			values : [ "助手" ]
		} ];
		var keywordchek = false;
		if (keywordArr && keywordArr.length > 0) {
			for ( var i = 0; i < keywordArr.length; i++) {
				var kw = keywordArr[i];
				if (fw(kw)) {
					keywordchek = true;
					break;
				}
			}
		}
		if (keywordchek) {
			value += '0';
		} else {
			value += '1';
		}
		if (value.indexOf('0') > -1) {
			aj();
		}
		return key + ':' + value;
	}

可以看到key无需计算,而value是经过计算得到的:具体的就是在页面上找是否有指定class的元素,是否有指定id的元素........也不知道12306是要干嘛,反正我是没理解这块的真正含义?但是可以分析出来,value最后的结果必然是“xxxx”,x代表0或1,但是显然12306不希望value中包含‘0’。那么也许可以直接用‘1111’来代替value吧~

到这里,登陆的逻辑就分析完了,想模拟登陆的童鞋可以自己动手试试了,这里提供一个思路吧,可以把encode32等函数拿到本地,然后用Java提供的js引擎执行一下~那么这个value就出来。

更深入

其实不仅仅是登陆,在各种提交表单的地方都加入了这么一个动态的key-value,具体的流程是这样的:

1、首先在加载页面时会引入一个动态的js文件,通过这个主要是拿到动态的key值,而计算value的逻辑都一样

2、在提交表单的时候会将这个动态的key和value也一并提交上去,若该参数出错,则会报“非法请求”错误

掌握了这些,从老版抢票软件升级到新版也不是什么难事了吧~

时间: 2024-08-03 21:37:45

12306新版抢票之逻辑分析的相关文章

12306 分流抢票 纯净绿色版

全程自动抢票,云打码自动识别验证码,多线程秒单.稳定捡漏,支持多天.多车次.短信提醒.??12306Bypass,12306分流抢票软件,完全免费的12306抢票软件,功能强易使用,全程自动抢票,云打码自动识别验证码,多线程秒单.稳定捡漏,支持多天.多车次.多席别.多乘客.短信邮件提醒等功能. ?2018年春运即将开启,根据火车票预售期为30天的规定,今天起,2018春运火车票正式发售,现在就可以购买2月1日(农历腊月十六),即春运首日的火车票了!1月17日可以购买除夕(2月15日)当天的火车票

python学习教程,12306火车票抢票系统

python学习教程,12306火车票抢票系统 代码展示: 1 ''' 2 在学习过程中有什么不懂得可以加我的python学习交流扣扣qun,934109170,群里有不错的学习教程.开发工具与电子书籍. 3 与你分享python企业当下人才需求及怎么从零基础学习好python,和学习什么内容. 4 ''' 5 import urllib.request as request 6 7 import http.cookiejar as cookiejar 8 9 import re 10 11 i

基于selenium+java的12306自动抢票

import java.util.concurrent.TimeUnit; import org.openqa.selenium.By;import org.openqa.selenium.Keys;import org.openqa.selenium.WebDriver;import org.openqa.selenium.WebElement;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.i

12306抢票软件连接地址

12306智能刷票,订票 https://github.com/testerSunshine/12306 12306 购票助手,支持集群,多账号,多任务购票以及 Web 页面管理 https://github.com/pjialin/py12306 12306分流抢票 https://www.bypass.cn/ 原文地址:https://www.cnblogs.com/Nanaya/p/12105505.html

归心似箭,IT达人分享抢票攻略

[51CTO专稿]随着春节一天天临近,“购票难”的问题也愈发凸显,猎豹.火狐.360等“春运抢票神器”占领了各大网站的重要版面,“技术抢票”成为炙手可热的话题,看看身为程序员的邓以克是如何抢到回家的票. 邓以克(@一路向西-phinecos)是一位进入IT行业3年的Java程序员:业务时间,比较喜欢研究技术,也写一些技术方面的文章. 其实去年12306推出以后,就有相应的刷票工具出来,邓以克谈到,自己也是从那个时候开始使用刷票工具,给 自己和身边的同事.朋友们顺利地买到回家的卧铺票的.今年,由于

春运到了,带你用python来抢票回家!

不知不觉,一年一度的春运抢票大幕已经拉开,想快速抢到回家的车票吗?作为程序员,这些技术手段,你一定要知道. 为了让大家更快捷更便利的抢火车票,各种各样的抢票软件应需而生,这类软件大部分都是付费抢票的机制. 作为程序员,如何用技术手段抢到回家的票?来看看用 Python 写的抢票脚本. 手把手教你用 Python 抢票回家过年 环境介绍 windows 8.1python3.6.1firefox插件 geckodriver.exe 操作步骤 引入要的模块 from selenium import

python3.7之12306抢票脚本实现

悲催的12306,彻底沦为各路抢票软件的服务提供方.元旦伊始,纯粹12306官网及APP抢票,愈一周的时间,仅到手一张凌晨3:55回家的站票.为远离脑残,无奈选择抢票软件,预购年后返沪车票.BTW,研究一下抢票脚本的实现思路,参考:(https://juejin.im/post/5b116504f265da6e0636cbc2 - Python3.6实现12306火车票自动抢票). 在原作者之上,对执行代码做了以下处理: 删除短信/邮件通知功能 删除控制台输入功能 新增登陆cookie的刷新 新

使用Python和Splinter实现12306火车票查询与抢票

有一段时间没有使用Python了,前几天经朋友提起一篇关于用Python实现抢火车票的文章,百度了实现抢火车票的技术细节,网上却有不少资料,也不是新鲜的东西.在了解了一些技术手段,阅读了一些大神的博文后,也尝试实现了一下,代码写得粗糙,纯当娱乐,本文在Windows系统下完成.需要提到的是,抢票过程中的验证码部分只能手动完成. 首先,我需要的工具和组件有: Chrome浏览器 浏览器驱动ChromeDriver Python 3.5 Web应用测试工具Splinter Chrome浏览器可自行下

12306改版之后简单抢票软件的实现(转载)

又到一年抢票时,各种抢票软件的肆虐让12306不堪重负,最近这几天12306频繁的更换手段来阻止抢票软件. 先来吐槽一下红红的验证码,过年的时候都喜欢用红色来喜庆一下,12306也深刻的表达了他的喜悦之情,又红又大的验证码啊,不过到底跨越了几个维度呢?看起来晕晕的,感觉像在时空里穿梭. 科学告诉我们,牛是色盲,分不出来颜色,但是伟大的黄牛们不是,不知道黄牛们看到鲜红的验证码之后会不会疯了一样的撞向显示器?那场面一定非常壮观 很快红色的验证码消失了,但是,在抢票的每一步都加了一个验证,过滤掉抢票软