赞
踩
热门演唱会门票不到一分钟就可能卖光,不知道要多快的手速才能一鼓作气点点点及时下单。走一下神可能就不得不选个差一点的区域,甚至只能高价求票了。
好朋友遇到了这样的烦恼,我一想这种比较机械的刷新其实很适合用脚本完成呀,所以就花了一个下午有了这个脚本。
目前还是比较有局限性的:
稳定性没有100%保证,如果是很重要的票可能一边开着电脑用脚本,一边自己用手机刷新更保险一些,做好两手准备
需要手动在脚本中修改人数
只支持大麦演唱会,不支持歌剧话剧,比赛等
不支持选座
需要事先登录好,填好相关的地址,人员信息
UI太粗糙啦
如果你想直接使用现成的脚本 → 从安装Tampermonkey到成功抢到演唱会门票
如果你对怎么写脚本感兴趣 → 怎么写一个抢票脚本
建议用Chrome浏览器使用这个脚本因为我就是在Chrome写的,其他浏览器没怎么测试,大家试用后有什么问题可以给我留言提意见反馈。
Tampermonkey可以很方便的开关脚本是否运行,抢完票后记得从Tampermonkey关掉脚本,不然浏览其他表演信息可能直接进入支付宝付账界面。
使用步骤
1. 用Chrome浏览器打开Tampermonkey官网,点击按钮下载安装
2. 关注公众号,发送dmtk取得脚本地址
3. 通过地址打开greasy fork的页面,点击安装按钮自动跳转到Tampermonkey
4. 点击安装按钮
5. 打开大麦网的页面,现在应该就可以看到按钮和提示了
6. 根据提示修改「大麦抢票-选场次票价人数」中people_num为相应人数
7. 刷新页面加载新版脚本
8. 点击想要的场次,票价
9. 点击“开始抢票”
10.等待提示音响起
11.支付宝付款
12.抢票成功~
如果报错
1. 可以打开开发者工具,如果报错一般是因为加载速度有点慢,可以适当放慢页面刷新速度或者换成更快的网络。
2. 如果出错建议运行前先清除localStorage中的isRunning。然后重新加载页面。
开始前的准备:
安装浏览器,比较推荐Chrome
安装Tampermonkey (详情见「从安装Tampermonkey到成功抢到演唱会门票」)
知道一点JavaScript
看看大麦网演唱会的网页是什么结构
观察大麦网购票流程
随便选一个演唱会页面看看。
观察大麦网演唱会购买网页我们可以发现当演唱会有票的时候,我们可以选择场次,选择票档,选择数量,点击「立即购买」(上图是预定票所以是「立即预订」),然后会跳转到确认页面,需要我们选择地址,观演人,支付方式然后按下按钮进行预订。如果只有一个默认地址,在确认页面实际需要我们做的只是点击选中观演人然后提交订单。
当票已经卖光或者还没有开始销售的时候按钮上的文字是「提交缺货登记」,「提交开售登记」,并且没有选择数量的地方。
思考抢票脚本流程
用户登录,填写地址,观演人信息
用户手动点击选择场次,票档 (为什么没有数量?因为需要抢票的页面没有选择数量的地方),在脚本中修改数量
用户点击「开始抢票」,脚本读取当前选择的场次,票档,
刷新页面,脚本点击相应场次,票档
检查有没有调节数量的控件出现,如果没有,回到4
根据脚本中数量调成数量控件
检查购买按钮上是否是「立即购买」字样,如果不是,回到4
点击「立即购买」按钮,跳转到确认页面
选择观演人
点击「同意以上协议并提交订单」 (同时发出声音提醒用户)
支付宝付款
成功抢到票~
需要我们写的是2-10的部分。Tampermonkey会根据url判断执行什么脚本,所以我们可以写两个文件。
大麦抢票-选场次票价人数 2-8
大麦抢票-确认 9-10
具体写法
大麦抢票-确认
从逻辑上来讲应该先写「大麦抢票-选场次票价人数」,但是「大麦抢票-确认」简单很多。所以先写这部分吧。
点击新建之后会出现一个模版文件。不要删掉上方的注释,非常重要。
// ==UserScript==// @name New Userscript// @namespace http://tampermonkey.net/// @version 0.1// @description try to take over the world!// @author You// @match https://www.example.com// @grant none// ==/UserScript==
具体每个字段的含义可以查询Tampermonkey官网。
// ==UserScript==// @name 大麦抢票-确认// @namespace https://www.jwang0614.top/scripts// @version 0.1// @description 辅助购买大麦网演唱会门票// @author Olivia Wang// @match https://buy.damai.cn/orderConfirm*// @grant none// ==/UserScript==
对我们来说最重要的是@match。其他@name,@description之类怎么填对我们要写的这个脚本执行都没有太大影响。@namespace是用来在@name相同时区分脚本的,可以用任何独特字符串,不过一般用自己个人主页url的比较多。
@match的重点是最后的*号通配符,这样只要url前面包含https://buy.damai.cn/orderConfirm, 无论Confirm之后跟的是什么有多长都能匹配上。不同网页的脚本@match的字符所规定的匹配规则会有变化。
具体代码:
(function() { 'use strict'; console.log("confirm"); // 点击观演人 var person = document.querySelector('#confirmOrder_1 > div.dm-ticket-buyer > div.ticket-buyer-select > div.next-row.next-row-no-padding.buyer-list > div > label > span.next-checkbox.isFirefox > span'); if (person) { person.click(); } // 播放提示音 var audio = new Audio("http://audio.marsupialgurgle.com/audio/successtrumpet.mp3"); audio.play(); // 提交订单 document.querySelector('#confirmOrder_1 > div.submit-wrapper > button').click();})();
虽然应该先成功提交再放庆祝提示音,但是点击提交后页面就跳转到支付宝了,所以这里是先播放提示音再点击提交订单。
有的确认页不需要选择观演人,所以要做个判断,不然在这一步会报错。
querySelector的那一长串直接用Chrome的开发者工具就可以获得:
点击红框中的按钮,然后在页面中点击选中你需要查看的元素,html中相关的元素会高亮显示。右键相应的html元素,选择复制selector,就可以得到那一长串字符了。
用document.querySelector就可以获取相应元素。
需要注意的是有些页面中元素会有变化,比如多一个少一个场次或者多一个少一个div什么的,直接复制的selector字符串可能含有类似:nth-child(6)的部分,这个数字可能会有变化,需要找到更加有普遍性的写法。比如根据有唯一classname的sibling节点定位之类的,大家可以多检查一下看看不同状态不同网页上selector是不是都能适用。
大麦抢票-选场次票价人数
还是以李荣浩的演唱会页面为例,url是https://detail.damai.cn/item.htm?spm=a2oeg.home.card_0.ditem_0.4b2a23e1sftIEo&id=594350362632。所以@match 写成 https://detail.damai.cn/*
就可以了。
我们可以把这个脚本分成几个部分
UI
开始抢票按钮
结束抢票按钮
提示
从页面获取用户输入场次票价
刷新
根据用户输入填入数据
判断能不能购买,如果可以点击按钮,如果不行再次刷新
LocalStorage
我们希望能刷新后保存用户场次票价人数信息,所以用到LocalStorage。
var people_num = 2;var isRunning = false;var storage = window.localStorage;storage.setItem("people_num", people_num);storage.setItem("isRunning", isRunning);
还没开票的页面也没有数量控件,所以通过脚本控制购票数量,储存到LocalStorage中。isRunning用来判断是不是在运行。
有的浏览器可能不太支持LocalStorage,可以在程序最开始判断一下.
if(!window.localStorage){ alert('不支持这个浏览器,请换成Chrome或者Safari。');}
UI
添加两个固定在页面上的按钮和一个提示栏。比如「开始抢票」按钮
// 创建一个p标签var start = document.createElement("P");// 添加文字start.appendChild(document.createTextNode("开始抢票"));// 设置格式,位置start.style.lineheight="50px";start.style.color="white";start.style.fontSize="30px";start.style.padding="10px 20px";start.style.background="green";start.style.position="fixed";start.style.right="30px";start.style.top="100px";// 保持在最上方start.style.zIndex="10000";// 获取dom中body元素var container = document.querySelector('body');// 将start按钮添加到dom中container.appendChild(start);
function get_numbers_from_page() { var event_selections = document.querySelectorAll('body > div.perform > div > div.flex1 > div.hd > div > div.order > div.perform__order__box > div.perform__order__select.perform__order__select__performs > div.select_right > div > div'); // 这里就用了sibling node定位 div.perform__desc__info + div // “+ div” 代表下一个div sibling var price_selections = document.querySelectorAll('body > div.perform > div > div.flex1 > div.hd > div > div.order > div.perform__order__box > div.perform__desc__info + div > div.select_right > div > div'); for (var i= 0;i < event_selections.length;i++) { // 通过class中是否含有active判断用户选择的是第几个选项,将结果数字保存在本地存储中 if (event_selections[i].classList.contains("active")) { storage.setItem("event_ele_num", i); } } for (var j= 0;j < price_selections.length;j++) { if (price_selections[j].classList.contains("active")) { storage.setItem("price_ele_num", j); } }}
一段时间后刷新页面
function timedRefresh(timeoutPeriod) { window.setTimeout("location.reload(true);",timeoutPeriod);}
填写数据,判断当前能不能购买
function set_up_check_page() { // 从storage中获取场次,票价,数量信息 var event_ele_num = storage.getItem("event_ele_num"); var price_ele_num = storage.getItem("price_ele_num"); var people_num = storage.getItem("people_num"); // 为了更直观地表现出“程序正在运行”,我把网页背景换了一个颜色 if (storage.getItem("isRunning") == "true") { document.querySelector('body > div.perform').style.background="darksalmon"; } // 获取所有的场次元素,点击相应元素选择 var event_selections = document.querySelectorAll('body > div.perform > div > div.flex1 > div.hd > div > div.order > div.perform__order__box > div.perform__order__select.perform__order__select__performs > div.select_right > div > div'); event_selections[event_ele_num].click(); var price_selections = document.querySelectorAll('body > div.perform > div > div.flex1 > div.hd > div > div.order > div.perform__order__box > div.perform__desc__info + div > div.select_right > div > div'); price_selections[price_ele_num].click(); // 判断有没有数量控件,如果有设定数量,如果没有继续刷新 var people_selection = document.querySelector(".cafe-c-input-number-input"); if (people_selection) { // 这里我用的是点击增加按钮,其实可以通过修改value的值实现 var people_inc_btn = document.querySelector('body > div.perform > div > div.flex1 > div.hd > div > div.order > div.perform__order__box > div:nth-child(6) > div.number_right > div > div > a.cafe-c-input-number-handler.cafe-c-input-number-handler-up'); for (var i =1; i < people_num; i++) { people_inc_btn.click(); } // 判断有没有“立即购买“按钮 var btn = document.querySelector("body > div.perform > div > div.flex1 > div.hd > div > div.order > div.perform__order__box > div:last-child > div"); if (btn) { if (btn.innerText == "立即购买") { // 点击立即购买按钮跳转到确认页 storage.removeItem("isRunning"); storage.removeItem("price_ele_num"); storage.removeItem("event_ele_num"); storage.removeItem("people_num"); storage.clear(); btn.click(); } } } // 如果正在抢票,0.4秒后刷新页面 if (storage.getItem("isRunning") == "true") { timedRefresh(400); }}
通过按钮控制脚本的开始和停止
// 开始抢票按钮start.onclick = function() { console.log('开始抢票!'); document.querySelector('body > div.perform').style.background="darksalmon"; storage.setItem("isRunning", true); get_numbers_from_page(); timedRefresh(600);};// 停止抢票按钮stop.onclick = function() { alert('停止抢票!'); document.querySelector('body > div.perform').style.background="white"; //storage.setItem("isRunning", false); storage.removeItem("isRunning");};
因为怕刷新太快来不及按「停止抢票」,我加入了快捷键。每个字母的keyCode可以在网上找到。
document.onkeydown = function() { var oEvent = window.event; if (oEvent.keyCode == 69 && oEvent.ctrlKey) { //alert("你按下了ctrl+E"); // start start.click(); }else if (oEvent.keyCode == 84 && oEvent.ctrlKey) { //alert("你按下了ctrl+T"); // stop stop.click(); }}
刷新
function reload_page() { // console.log("reload"); window.setTimeout(set_up_check_page,800);}
组合
将以上内容补全完整组合到一起就可以啦,完整的代码请关注下方公众号,输入dmtk获取下载地址。
有什么问题和意见欢迎大家在下面给我留言~如果脚本运行出了什么问题也可以告诉我,我看看能不能改一改。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。