网站首页 > 开源技术 正文
作者:西岚
转发链接:https://juejin.im/post/5dadd0236fb9a04de04d968e
目录
Node.js 实现抢票小工具&短信通知提醒(下)「干货」 本篇
开发购票功能
首先我们在init方法里做个判断,如果有余票才去购票,没有余票购个毛
class QueryTicket{
constructor({ data, phoneNumber, cookie, day }) {
//constructor代码...
}
//初始化
async init(){
let ticketList = await this.handleQueryTicket()
//如果有余票
if (ticketList.length) {
//把余票传入购票逻辑方法,返回短信通知所需要的数据
let resParse = await this.handleBuyTicket(ticketList)
}
}
//查询余票的逻辑
async handleQueryTicket(){
// 查询余票代码...
}
//调用查询余票接口
requestTicket(){
//调用查询余票接口代码...
}
//购票相关逻辑
async handleBuyTicket(ticketList){
let year = new Date().getFullYear() //年份,
let month = new Date().getMonth() + 1 //月份,拼接购票日期用得上,因为余票接口只返回几号
let {
onStationName,//起始站点名
offStationName,//结束站点名
lineId,//线路id
vehTime,//发车时间
startTime,//预计上车时间
onStationId,//上车的站台id
offStationId //到站的站台id
} = this.data // 初始化的数据
let station = `${onStationName}-${offStationName}` //站点,发短信时候用到:"宝安交通局-深港产学研基地"
let dateStr = ""; //车票日期
let tickAmount = "" //总张数
ticketList.forEach(item => {
dateStr = dateStr + `${year}-${month}-${item.day},`
tickAmount = tickAmount + `${item.ticketLeft}张,`
})
let buyTicket = {
lineId,//线路id
vehTime,//发车时间
startTime,//预计上车时间
onStationId,//上车的站点id
offStationId,//目标站点id
tradePrice: '5', //金额
saleDates: dateStr.slice(0, -1),
payType: '2' //支付方式,微信支付
}
// 调用购票接口
let data = querystring.stringify(buyTicket)
let res = await this.requestOrder(data) //返回json数据,是否购票成功等等
//把发短信所需要数据都要传入
return Object.assign({}, JSON.parse(res.data), { queryParam: { dateStr, tickAmount, startTime, station } })
}//购票相关逻辑
//调用购票接口
requestOrder(obj){
return axios.post('http://weixin.xxxx.net/ebus/front/wxQueryController.do?BcTicketBuy', obj, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12A365 MicroMessenger/5.4.1 NetType/WIFI",
"Cookie": this.cookie
}
})
}
handleInfoUser(){}//通知用户的逻辑
sendMSg(){} //发短信接口
}
复制代码
到这里,查询余票,购票这两个核心操作已经完成。
目前还剩下,如何通知用户是否购票成功。
之前我尝试过使用qq邮箱的smtp服务,抢票成功后发送邮件通知,但是我觉得吧,并不好用,主要是我没有打开邮箱的习惯,没网也收不到,所以,并没有采纳这个方案。
加上之前我注册过企业认证的公众号,腾讯云免费送了我1000条短信通知,而且短信也比较直观,所以我这里就安装腾讯云的SDK,部署了一套发短信的功能。
腾讯云短信的相关内容
其实看看文档就行了,我也是copy文档,注意看短信单发那部分
https://cloud.tencent.com/document/product/382/3772
如果跟我一样有企业认证的话,看快速入门这里就行了,一步步跟着操作
看下短信正文,{Number}这些里面的数字是变量。
就是说短信的模板是固定的,但是里面有{Number}的内容可以自定义
调用的时候,里面的数字对应着传过去的参数数组序号,{1}代表数组[0]参数,以此类推
提交审核,审核一般很快就通过,也就是几十万毫秒吧
开发通知功能
class QueryTicket{
constructor({ data, phoneNumber, cookie, day }) {
//constructor代码...
}
//初始化
async init(){
let ticketList = await this.handleQueryTicket()
//如果有余票
if (ticketList.length) {
//把余票传入购票逻辑方法,返回短信通知所需要的数据
let resParse = await this.handleBuyTicket(ticketList)
//执行通知逻辑
this.handleInfoUser(resParse)
}
}
//查询余票的逻辑
async handleQueryTicket(){
// 查询余票代码...
}
//调用查询余票接口
requestTicket(){
//调用查询余票接口代码...
}
//购票相关逻辑
async handleBuyTicket(ticketList){
//购票代码...
}
//调用购票接口
requestOrder(obj){
//购票接口请求代码...
}
//通知用户的逻辑
async handleInfoUser(parseData){
//获取上一步购票的response数据和我们拼接的数据
let { returnCode, returnData: { main: { lineName, tradePrice } }, queryParam: { dateStr, tickAmount, startTime, station } } = parseData
//如果购票成功,则返回500
if (returnCode === "500") {
let res = await this.sendMsg({
dateStr, //日期
tickAmount: tickAmount.slice(0, -1), //总张数
station, //站点
lineName, //巴士名称/路线名称
tradePrice,//总价
startTime,//出发时间
phoneNumber: this.phoneNumber,//手机号
})
//如果发信成功,则不再进行抢票操作
if (res.result === 0 && res.errmsg === "OK") {
this.setStop(true)
} else {
//失败不做任何操作
console.log(res.errmsg)
}
} else {
//失败不做任何操作
console.log(resParse['returnInfo'])
}
}
//发短信接口
sendMSg(){
let { dateStr, tickAmount, station, lineName, phoneNumber, startTime, tradePrice } = obj
let appid = 140034324; // SDK AppID 以1400开头
// 短信应用 SDK AppKey
let appkey = "asdfdsvajwienin23493nadsnzxc";
// 短信模板 ID,需要在短信控制台中申请
let templateId = 7839; // NOTE: 这里的模板ID`7839`只是示例,真实的模板 ID 需要在短信控制台中申请
// 签名
let smsSign = "测试短信"; // NOTE: 签名参数使用的是`签名内容`,而不是`签名ID`。这里的签名"腾讯云"只是示例,真实的签名需要在短信控制台申请
// 实例化 QcloudSms
let qcloudsms = QcloudSms(appid, appkey);
let ssender = qcloudsms.SmsSingleSender();
// 这里的params就是短信里面可以自定义的内容,也就是填入{1}{2}..的内容
let params = [dateStr, station, lineName, startTime, tickAmount, tradePrice];
//用promise来封装下异步操作
return new Promise((resolve, reject) => {
ssender.sendWithParam(86, phoneNumber, templateId, params, smsSign, "", "", function (err, res, resData) {
if (err) {
reject(err)
} else {
resolve(resData)
}
});
})
}
}
复制代码
如果发信成功,返回result:0
到这里,大部分需求已经完成了,还剩下一个定时任务
定时任务
也声明一个类,这里我们用到的是schedule
// 定时任务
class SetInter {
constructor({ timer, fn }) {
this.timer = timer // 每几秒执行
this.fn = fn //执行的回调
this.rule = new schedule.RecurrenceRule(); //实例化一个对象
this.rule.second = this.setRule() // 调用原型方法,schedule的语法而已
this.init()
}
setRule() {
let rule = [];
let i = 1;
while (i < 60) {
rule.push(i)
i += this.timer
}
return rule //假设传入的timer为5,则表示定时任务每5秒执行一次
// [1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56]
}
init() {
schedule.scheduleJob(this.rule, () => {
this.fn() // 定时调用传入的回调方法
});
}
}
复制代码
多个用户抢票
假设我们有两个用户要抢票,所以定义两个obj,实例化下QueryTicket类
data: { //用户1
lineId: 111130,
vehTime: 0722,
startTime: 0751,
onStationId: 564492,
offStationId: 17990,
onStationName: '宝安交通运输局③',
offStationName: "深港产学研基地",
tradePrice: 0,
saleDates: '',
beginDate: '',
},
phoneNumber: 123123123,
cookie: 'JSESSIONID=TESTCOOKIE',
day: "17"
}
let obj2 = { //用户2
data: {
lineId: 134423,
vehTime: 1820,
startTime: 1855,
onStationId: 4322,
offStationId: 53231,
onStationName: '百度国际大厦',
offStationName: "裕安路口",
tradePrice: 0,
saleDates: '',
beginDate: '',
},
phoneNumber: 175932123124,
cookie: 'JSESSIONID=TESTCOOKIE',
day: ""
}
let ticket = new QueryTicket(obj) //用户1
let ticket2 = new QueryTicket(obj2) //用户2
new SetInter({
timer: 1, //每秒执行一次,建议5秒,不然怕被ip拉黑,我这里只是为了方便下面截图
fn: function () {
[ticket,ticket2].map(item => { //同时进行两个用户的抢票
if (!item.getStop()) { //调用实例的原型方法,判断是否停止抢票,如果没有则继续抢
item.init()
} else { // 如果抢到票了,则不继续抢票
console.log('stop')
}
})
}
})
复制代码
node index.js 运行下,跑起来了
如果他抢到票的话,我就会收到短信通知:
打开手机,看下订单信息
搞定,收工
写在最后
其实可以在此基础上还能添加更多功能,比如直接抓取登录接口获取cookie,指定路线抢票,还有错误处理啊啥的
值得注意的是,请求接口不能太频繁,最好控制在5秒一次的频率,不然会给别人造成困扰,也容易被ip拉黑
推荐JavaScript学习相关文章
《学习 jQuery 源码整体架构,打造属于自己的 js 类库》
《Angular v10.0.0 正式发布,不再支持 IE9/10》
《「实践」浏览器中的画中画(Picture-in-Picture)模式及其 API》
《「多图」一文带你彻底搞懂 Web Workers (上)》
《「多图」一文带你彻底搞懂 Web Workers (中)》
《webpack4主流程源码解说以及动手实现一个简单的webpack(上)》
《webpack4主流程源码解说以及动手实现一个简单的webpack(下)》
《前后端全部用 JS 开发是什么体验(Hybrid + Egg.js经验分享)上》
《前后端全部用 JS 开发是什么体验(Hybrid + Egg.js经验分享)中》
《前后端全部用 JS 开发是什么体验(Hybrid + Egg.js经验分享)下》
《一文带你搞懂 babel-plugin-import 插件(上)「源码解析」》
《一文带你搞懂 babel-plugin-import 插件(下)「源码解析」》
《教你如何使用内联框架元素 IFrames 的沙箱属性提高安全性?》
《细说DOM API中append和appendChild的三个不同点》
《NodeX Component - 滴滴集团 Node.js 生态组件体系「实践」》
《浅谈浏览器架构、单线程js、事件循环、消息队列、宏任务和微任务》
《了不起的 Webpack HMR 学习指南(上)「含源码讲解」》
《了不起的 Webpack HMR 学习指南(下)「含源码讲解」》
《图解 Promise 实现原理(二):Promise 链式调用》
《图解 Promise 实现原理(三):Promise 原型方法实现》
《图解 Promise 实现原理(四):Promise 静态方法实现》
《使用Service Worker让你的 Web 应用如虎添翼(上)「干货」》
《使用Service Worker让你的 Web 应用如虎添翼(中)「干货」》
《使用Service Worker让你的 Web 应用如虎添翼(下)「干货」》
《一个轻量级 JavaScript 全文搜索库,轻松实现站内离线搜索》
《细品269个JavaScript小函数,让你少加班熬夜(一)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(二)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(三)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(四)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(五)「值得收藏」》
《细品269个JavaScript小函数,让你少加班熬夜(六)「值得收藏」》
《手把手教你7个有趣的JavaScript 项目-上「附源码」》
《手把手教你7个有趣的JavaScript 项目-下「附源码」》
《JavaScript 使用 mediaDevices API 访问摄像头自拍》
《一文彻底搞懂JavaScript 中Object.freeze与Object.seal的用法》
《可视化的 JS:动态图演示 - 事件循环 Event Loop的过程》
《可视化的 js:动态图演示 Promises & Async/Await 的过程》
《Pug 3.0.0正式发布,不再支持 Node.js 6/8》
《通过发布/订阅的设计模式搞懂 Node.js 核心模块 Events》
《「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能》
《JavaScript 已进入第三个时代,未来将何去何从?》
《前端上传前预览文件 image、text、json、video、audio「实践」》
《深入细品 EventLoop 和浏览器渲染、帧动画、空闲回调的关系》
《推荐13个有用的JavaScript数组技巧「值得收藏」》
《36个工作中常用的JavaScript函数片段「值得收藏」》
《一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」》
《手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件》
《JavaScript正则深入以及10个非常有意思的正则实战》
《前端开发规范:命名规范、html规范、css规范、js规范》
《100个原生JavaScript代码片段知识点详细汇总【实践】》
《手把手教你深入巩固JavaScript知识体系【思维导图】》
《一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧》
《身份证号码的正则表达式及验证详解(JavaScript,Regex)》
《127个常用的JS代码片段,每段代码花30秒就能看懂-【上】》
《深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】》
《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》
《面试中教你绕过关于 JavaScript 作用域的 5 个坑》
作者:西岚
转发链接:https://juejin.im/post/5dadd0236fb9a04de04d968e
猜你喜欢
- 2024-11-17 游戏编程 | THREE.JS实现游戏操作界面
- 2024-11-17 如何处理 Node.js 中出现的未捕获异常?
- 2024-11-17 10个实用的JS技巧「值得收藏」(js快速入门教程)
- 2024-11-17 细品原生JS从初级到高级知识点汇总(四)
- 2024-11-17 奇葩搞怪GIF动图,这样恶搞小姐姐真的好吗?
- 2024-11-17 推荐三款正则可视化工具「JS篇」(正则视维)
- 2024-11-17 3种Javascript图片预加载的方法详解
- 2024-11-17 高性能多级多选级联组件开发「JS篇」
- 2024-11-17 44道JavaScript送命题(javascript逻辑题)
- 2024-11-17 web前端:原生js全动画企业官网,开机动画、切屏/分屏动画
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)