自制抢票脚本刷车位——全方位买车位指南
当你结束了一整天的工作,托着疲惫的身子开车回到小区楼下,发现楼下的车位早已停满了车。于是你只好一圈圈的在车库里寻找着哪里还有尚未被占领的一小块区域。你一边诅咒为什么只有自己的公司才天天加班,一边又渴望拥有一个专属于自己的小车位。
终于,就在几天前,物业通知地下负二层的车位将在近期开售!开卖的方式竟然跟双十一秒杀一样——可以提前把想买的位置放到购物车中,然后到点开抢。
作为一个会讲段子的 Coder,我决定写一个脚本来提高这件事的成功率。
1、 实地考察
切记,一定要实地考察!一定要实地考察!一定要实地考察!
永远不要相信所谓参考手册或者示意图,只有当你真正去实地考察了之后,你才会明白,为什么同样面积的两个车位,其中一个的价钱却便宜三分之一。
如果有条件的话,最好把自己的车子开过去试停一下,宽度相差 20cm 的两个车位可能很难用肉眼分辨出来,但不管是从对于新手司机的友好度来说,还是从下车后车门的展开度来说,这个距离都很重要。把车子开过去一试便知。
2、抢最方便的车位
很多人在抢车位的时候有一个误区,那就是离电梯越近的车位越好。
诚然,距离的远近是一个很重要的衡量指标,但“ 最近的”车位并不等同于“ 最方便”的车位。
所谓最方便的车位,首先应该是停车时方便。比如车位在你进入车库后最短行驶路线的右手侧,这样你在进出车位时不会影响到对向来车。同时,还要考虑到车位四周的障碍物,在停车过程中是否会造成干扰;停车后是否会阻碍左右车门及后备箱的开关。临近车位汽车是否容易刮蹭到自己,特别是开门时。
最后,将以上所有因素和车位的售价结合起来考虑,得到符合自己心意的车位排序。(土豪除外,土豪只需要简单的按价格排序就好了)
3. 分析网站
登录网站后我们可以看到,点击车位编号前面的 ❤️ 表示关注该车位,类似于加入到购物车中。
然后进入关注列表,点击编号后面的 参与选房
,在弹出的侧滑页面中点击 一键选房
,再确认,即可完成选房。(全程无验证码)
通过分析网站自带的 js 脚本,可以得知在购买时间未到时、购买失败时以及购买成功时的页面提示信息。
至此,脚本的思路已经基本成熟。
4、编写、调试
实现的方法有很多,我这里尝试了三种,其实都有异曲同工之处。
方法一
因为没有验证码,所以最简单的办法就是通过 js 模拟点击,最终达到自动刷新检测的效果。
JS 示例代码:
var len = $('td.alright > a').length;
var index = 0;
$('td.alright > a')[index].click();
var id = $('#TargetID').prop('value');
var idInterval = setInterval(
function(){
id = $('#TargetID').prop('value');
if(id == undefined){
console.log('=== 等待页面加载中 ===');
}else{
var number = $('.detail-header > span').text();
var className = $('#btn_group > a').prop('className');
if(className =='add_price_over'){
console.log('===【'+number+'】无货,准备抢购下一个===');
if(index < len){
index = index + 1;
$('td.alright > a')[index].click();
id = undefined;
}
}else if(className == 'quick_price'){
$('#btn_group > a').click();
$('body > div.modal.small-modal.modal-helpers > div.modal-footer > a.btn.btn-default.btn-primary').click();
console.log('===【'+number+'】抢票成功!===');
console.log('=== 脚本即将停止 ===');
clearInterval(idInterval);
}else{
console.log('=== 未识别! ===');
}
}
},500);
上面是此次抢车位的完整版代码,这里简单提几个关键点:
- 因为原站点引用了 jQuery,所以选择 DOM 元素时,直接用 jQuery 语法即可;
- 由于页面上用到许多 Ajax 动态加载到内容,所以模拟点击后,要等待一段时间才能检测到弹出页面上的元素,这里用到
setInterval
定时器,只有在检测到动态页面加载完成后,才执行后续操作; - 一定要在合适的地方清楚定时器,否则会在后台一直运行;万一误下单,那可是随便十几万就没了。
登录页面,进入购物车,然后把上面的代码拷贝到 Chrome 下的 Snippets 中,并运行,看到的效果如图所示:
P.S.
如果对方的网站没有引用 jQuery 的话,那么你可以在最开始的地方增加如下代码:
javascript: (function(e, s) {
e.src = s;
e.onload = function() {
jQuery.noConflict();
};
document.head.appendChild(e);
})(document.createElement('script'), '//code.jquery.com/jquery-latest.min.js');
如果你想做到让脚本自动检测时间并刷新的话,可以参考下面的代码逻辑:
var deadline=new Date(2017,0,21,1,23);
var diffs=null;
var t=setInterval(function(){
var now=new Date();
var diffms=deadline.getTime()-now.getTime();
console.log(diffms)
if(diffms<5001){
console.log("开始加速...")
setInterval(yourFunction,500)
}else{
diffs=diffms/1000;
console.log("剩余"+parseInt(diffs/60)+"分"+parseInt(diffs%60)+"秒")
}
},5000)
它会每5s检测一次时间,当距离 deadline 只剩 5s 时,开始每 0.5s 执行一次模拟点击脚本。
方法二
如果有验证码,那么可以先抓包分析,然后通过 js 直接发送 get/post 请求。
JS 示例代码:
function httpGetAsync(theUrl, id,callback)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
callback(id,xmlHttp.responseText);
}
xmlHttp.open("GET", theUrl, true); // true for asynchronous
xmlHttp.send(null);
}
上面是一个异步请求函数,post 方法同理,因为无需处理 Cookie,但是要处理好 post 的返回操作,禁止页面发生跳转。
方法三
思路跟方法二一致。可能是由于我对 js 用的不熟,所以写起来总觉得不那么得心应手。那么我们可以换成自己熟悉的语言,python、Java等都可以。
与方法二唯一的区别时,这种方法相当于自己编写客户端来发包收包,所以需要我们自己手动维护登录 Cookie。在抓包分析时,也需要格外仔细,除了需要关注正常的提交数据外,还要留意是否有验证性 token 的存在。
比如我发现这个抢车位的网站在提交 Url 时会自带一个时间戳,在发送 post 请求时,会将页面中的一个 token 传入作为验证。所以我们需要通过脚本模拟生成时间戳,并提取页面中隐藏的 token。
Python 示例代码:
# 获取对应车位的 Url
def getUrl(num):
url = 'http://xxx.com/ActivityTarget/Auction/' + str(num) + '?site=7&pageslide=true&random=' + str(int(time.time()))
return url
# 获取抢车位时的动态价格信息和验证信息
def getPriceToken(content):
# print content
p1 = re.compile(r'<input type="hidden" id="currentprice" value="(.*?)" />', re.M)
price = p1.findall(content)[0]
# print price
p2 = re.compile(r'<input name="__RequestVerificationToken" type="hidden" value="(.*?)" />', re.M)
token = p2.findall(content)[0]
# print token
if price and token:
return [price,token]
else:
return None
其他方法
还有一些方法,比如利用自动化 Web 测试工具也可以做到自动刷新、下单的功能。
考虑到手机浏览器对 javascript 的支持能力,很多网站的移动端在安全性上做的比较薄弱。所以当我们遇到验证方式过于复杂直接从 PC Web 端难以下手时,也可以通过写 Android 端的控制脚本来自动刷新。至于脚本本身,与在 PC 上运行的并无大异。