亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Node.js 實(shí)現(xiàn)搶票小工具 & 短信通知提醒功能

 更新時(shí)間:2019年10月22日 10:30:23   作者:nodejs  
這篇文章主要介紹了Node.js 實(shí)現(xiàn)搶票小工具 & 短信通知提醒功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

要知道在深圳上班是非常痛苦的事情,特別是我上班的科興科技園這一塊,去的人非常多,每天上班跟春運(yùn)一樣,如果我能換到以前的大沖上班那就幸福了,可惜,換不得。

尤其是我這個(gè)站等車的多的一筆,上班公交擠的不行,車滿的時(shí)候只有少部分人能硬擠上去。通常我只會用兩個(gè)字來形容這種人:“公交怪”

想當(dāng)年我朋友瘦的像只猴還能上去,老子身高182體重72kg擠個(gè)公交,不成問題,反手一個(gè)阻擋,悶聲發(fā)大財(cái),前面的阿姨你快點(diǎn)阿姨,別磨磨唧唧的,快上去啊阿姨,嗯?你還想擠掉我?你能擠掉我?你能擠掉我!我當(dāng)場!把車吃了!

....

咳咳,擠公交是不可能擠公交滴,因?yàn)榻裉煳野l(fā)現(xiàn)了一個(gè)可以定制路線的網(wǎng)約巴士公眾號【深圳xxx】

但是呢,票經(jīng)常會被搶光,同時(shí)我還我發(fā)現(xiàn),有時(shí)候會有人退票,這時(shí)候就有空余票了,關(guān)鍵是我不可能時(shí)時(shí)都在公眾號上盯著,于是,我就寫了一個(gè)搶票+短信通知的小工具

獲取接口信息

1.查看頁面結(jié)構(gòu)

這個(gè)就是訂票頁面,顯示當(dāng)前月的車票情況,根據(jù)圖示,紅色為已滿,綠色為已購,灰色為不可選

如果是可選就是白色的小方塊,并且在下面顯示余票,如下圖所示:

我們打算這么做,

  1. 定時(shí)抓取返回的接口信息
  2. 根據(jù)接口返回值判斷是否有余票

好,審查下源代碼看下接口信息,等等,微信瀏覽器沒辦法審查源代碼,于是

2.使用chrome調(diào)試微信公眾號網(wǎng)頁頁面

首先面臨個(gè)問題,如果直接copy公眾號網(wǎng)頁Url在chrome打開的話,就會顯示這個(gè)畫面,他被302重定向到了這個(gè)頁面,所以是行不通的,只有獲取OAuth2.0授權(quán)才能進(jìn)去

所以我們得先通過抓包工具,知道手機(jī)訪問微信公眾號網(wǎng)頁的時(shí)候,需要帶什么信息過去,這時(shí)候我們就得借助抓包工具,因?yàn)槲译娔X是Mac,用不了 Fiddler ,我用的是 Charles 花瓶,就是下面這位仁兄

借助這個(gè)工具,我們只需3步就可以輕松搞定手機(jī)數(shù)據(jù)抓包:

  • 獲取本機(jī)IP地址和端口
  • 設(shè)置代理手機(jī)上網(wǎng)
  • 依次執(zhí)行上面兩步

2-1 獲取本機(jī)IP地址和端口

第一步,找到端口號,一般默認(rèn)是8088,但是為了確認(rèn)可以打開 Proxy / Proxy Setting 看下,哦原來我之前設(shè)置成了8888

然后找到 Charleshelp / Local IP Address,點(diǎn)擊它就會看到自己的本機(jī)地址,找到本機(jī)地址記下來,然后進(jìn)行下一步

2-2設(shè)置代理手機(jī)上網(wǎng)

首先保證手機(jī)跟電腦連接的是同一個(gè)wifi,然后在wifi設(shè)置那里會有設(shè)置代理信息,比如我的猴米...不對,小米9手機(jī)!設(shè)置如下:

輸入上一步獲取主機(jī)名,端口號就ok了

輸入完成,點(diǎn)擊確定后。 Charles 就會彈出一個(gè)對話框,問你是否同意接入代理,點(diǎn)擊確定allow就行了。

2-3 用手機(jī)訪問目標(biāo)網(wǎng)頁

我們用手機(jī)訪問微信公眾號【深圳x出行】進(jìn)入到搶票頁面后,發(fā)現(xiàn) Charles 已經(jīng)成功抓包到了網(wǎng)頁信息,當(dāng)我們進(jìn)入這個(gè)搶票頁面的時(shí)候,他會發(fā)起兩個(gè)請求,一個(gè)是獲取document文檔內(nèi)容,一個(gè)post請求獲取票務(wù)信息。

仔細(xì)分析了下,大概明白了業(yè)務(wù)邏輯:

整個(gè)項(xiàng)目技術(shù)站是java+jsp,傳統(tǒng)寫法,用戶身份驗(yàn)證主要是cookie+session方案,前端這一塊主要是使用 jQuery

當(dāng)用戶進(jìn)入頁面的時(shí)候,會攜帶查詢參數(shù),如起始站點(diǎn),時(shí)間,車次等信息和cookie請求document文檔, 也就是圈起來的這一塊,

而我們想要的核心內(nèi)容:日歷表,一開始是不顯示的

因?yàn)檫€要在請求一次

第二次請求,攜帶cookie和以上的查詢參數(shù)發(fā)起一個(gè)post請求,獲取當(dāng)月的車票信息,也就是日歷表內(nèi)容

下面這個(gè)是請求當(dāng)月票務(wù)信息,然而發(fā)現(xiàn)他返回的是一堆html節(jié)點(diǎn)

好吧...估計(jì)是獲取到之后直接 appenddiv 里面的,然后渲染生成日歷表內(nèi)容

接著在手機(jī)上操作,選擇兩個(gè)日期,然后點(diǎn)擊下單,發(fā)送購票請求,拉取購票接口,我們看下購票接口的請求和返回內(nèi)容:

看下request 內(nèi)容,根據(jù)字段的意思大概明白是線路,時(shí)間,以及車票金額,還有支付方式

在看看返回的內(nèi)容:返回一個(gè)json字符串?dāng)?shù)據(jù),里面大概涵蓋了下單的成功返回碼,時(shí)間,id號等等信息

2-4 記錄所需要的信息內(nèi)容

根據(jù)上面的分析,總結(jié)下內(nèi)容: 整個(gè)項(xiàng)目用戶身份驗(yàn)證是使用 cookiesession 方案,請求數(shù)據(jù)用的是 form data 方式,請求字段啥的我們也都清楚,唯獨(dú)有一點(diǎn),就是請求余票的時(shí)候,返回的是html節(jié)點(diǎn)代碼,而不是我們預(yù)期的json數(shù)據(jù),這樣就有個(gè)麻煩,我們沒辦法一目了然的明白他余票的時(shí)候是如何顯示的

所以我們只能通過 chrome 進(jìn)行調(diào)試,才能得出他是如何判斷余票的。

我們找個(gè)記事本,記錄下信息,記錄的內(nèi)容有:

  • 請求余票接口和購票接口的 url 地址
  • cookie 信息 各自的 request 參數(shù)字段 user-Agent 信息
  • 各自的 response 返回內(nèi)容

2-5 設(shè)置chrome

有以上信息后,我們就可以開始用chrome調(diào)試了, 首先打開 More tools / Network conditions

user-Agent 填入到 Custom里面

2-6 Charles抓包本地請求

因?yàn)槲覀円勋@取到的cookie填入到chrome里面,以我們的用戶身份去訪問網(wǎng)頁,所以我們需要在請求目標(biāo)地址的時(shí)候,改包修改cookie

首先我們需要開啟 macOS Proxy ,抓包我們的http請求

打開chrome訪問目標(biāo)網(wǎng)址,我們可以看到 Charles

上已經(jīng)抓包到了我們訪問的目標(biāo)url地址,然后給目標(biāo)url地址打上斷點(diǎn),方便調(diào)試

然后再次訪問,這時(shí)候斷點(diǎn)就生效了,彈出一個(gè)tab名為 break points ,可以看到之所以我們還是不能訪問到目標(biāo)網(wǎng)址,是因?yàn)?sessionId 不對,所以我們把抓取到的 cookie 在填入到里面,點(diǎn)擊 execute

這時(shí)候,能夠正確跳到目標(biāo)頁面了。

大概看了下他整體布局,和 jQuery 代碼 CSS

代碼,特別是日歷表那一塊

審查了下元素發(fā)現(xiàn):

小方塊的結(jié)構(gòu)為:

<td class="b">
<span>這里為日期</span>
<span>如果有余票則顯示余票數(shù)量</span>
</td>
  • td的樣式名為 a 代表不可選
  • 樣式名為 e 代表已滿
  • 樣式名為 d 代表已購
  • 樣式名為 b 則是我們要找的,代表可選,也就是有余票

到這一步,整個(gè)購票流程就清楚了

到時(shí)候我們通過Node.js請求的時(shí)候,處理返回?cái)?shù)據(jù),用正則去判斷是否有余票的class名 b ,有余票的話,在獲取div里面的余票數(shù)量內(nèi)容就Ok了

2.Node.js 請求目標(biāo)接口

 2-1 分析需要開發(fā)的功能點(diǎn)

寫代碼之前我們需要想好功能點(diǎn),我們需要什么功能:

  • 請求余票接口
  • 定時(shí)請求任務(wù)
  • 有余票則自動請求購票接口下訂單
  • 調(diào)用騰訊云短信api接口發(fā)送短信通知
  • 多個(gè)用戶搶票功能
  • 搶某個(gè)日期的票

首先 mkdir ticket 創(chuàng)建名為ticket的文件夾,接著 cd ticket 進(jìn)入文件夾 npm init 一路瞎幾把回車也無妨。 下面開始安裝依賴,根據(jù)上面的功能需求,我們大概需要:

1.請求工具,這里看個(gè)人習(xí)慣,你也可以使用原生的 http.request ,我這里選擇用的是 axios ,畢竟 axios 在node端底層也是調(diào)用 http.request

cnpm install axios --save

2.定時(shí)任務(wù) node-schedule

cnpm install node-schedule --save

3.node端選擇dom節(jié)點(diǎn)工具 cheerio

cnpm install cheerio --save

4.騰訊發(fā)短信的依賴包 qcloudsms_js

cnpm install qcloudsms_js

5.熱更新包,諾豆的媽媽, nodemom (其實(shí)不用也可以)

cnpm install nodemom --save-dev

2-2開發(fā)請求余票接口

接著 touch index.js 創(chuàng)建核心js文件,開始編碼:

首先引入所有依賴

const axios = require('axios')
const querystring = require("querystring"); //序列化對象,用qs也行,都一樣
var QcloudSms = require("qcloudsms_js");
var cheerio = require('cheerio');
var schedule = require('node-schedule');

然后我們先定義請求參數(shù),來一個(gè)obj

var obj = {
 data: {
  lineId: 111130, //路線id
  vehTime: 0722, //發(fā)車時(shí)間,
  startTime: 0751, //預(yù)計(jì)上車時(shí)間
  onStationId: 564492, //預(yù)定的站點(diǎn)id
  offStationId: 17990,//到站id
  onStationName: '寶安交通運(yùn)輸局③', //預(yù)定的站點(diǎn)名稱
  offStationName: "深港產(chǎn)學(xué)研基地",//預(yù)定到站名稱
  tradePrice: 0,//總金額
  saleDates: '17',//車票日期
  beginDate: '',//訂票時(shí)間,滯空,用于抓取到余票后填入數(shù)據(jù)
 },
 phoneNumber: 123123123, //用戶手機(jī)號,接收短信的手機(jī)號
 cookie: 'JSESSIONID=TESTCOOKIE', // 抓取到的cookie
 day: "17" //定17號的票,這個(gè)主要是用于搶指定日期的票,滯空則為搶當(dāng)月所有余票
}

接著聲明一個(gè)名為 queryTicket 的類,為啥要用類呢,因?yàn)榛诘谖鍌€(gè)需求點(diǎn),多個(gè)用戶搶票的時(shí)候,我們分別 new 一下就行了,

同時(shí)我們希望能夠記錄請求余票的次數(shù),和當(dāng)搶到票后自動停止查詢余票得操作,所以給他加上個(gè)計(jì)數(shù)變量 times 和是否停止的變量,布爾值 stop

編寫代碼:

class QueryTicket{
 /**
  *Creates an instance of QueryTicket.
  * @param {Object} { data, phoneNumber, cookie, day }
  * @param data {Object} 請求余票接口的requery參數(shù)
  * @param phoneNumber {Number} 用戶手機(jī)號,短信需要用到
  * @param cookie {String} cookie信息
  * @params day {String} 某日的票,如'18'
  * @memberof QueryTicket 請求余票接口
  */
 constructor({ data, phoneNumber, cookie, day }) {
  this.data = data 
  this.cookie = cookie
  this.day = day
  this.phoneNumber = phoneNumber
  this.postData = querystring.stringify(data)
  this.times = 0;  //記錄次數(shù)
  var stop = false //通過特定接口才能修改stop值,防止外部隨意串改
  this.getStop = function () { //獲取是否停止
   return stop 
  }
  this.setStop = function (ifStop) { //設(shè)置是否停止
   stop = ifStop
  }
 }
}

下面開始定義原型方法,為了方便維護(hù),我們把邏輯拆分成各個(gè)函數(shù)

class QueryTicket{
 constructor({ data, phoneNumber, cookie, day }) {
 //constructor代碼... 
 }
  init(){}//初始化
  handleQueryTicket(){}//查詢余票的邏輯
  requestTicket(){} //調(diào)用查詢余票接口
  handleBuyTicket(){} //購票相關(guān)邏輯
  requestOrder(){}//調(diào)用購票接口
  handleInfoUser(){}//通知用戶的邏輯
  sendMSg(){} //發(fā)短信接口
}

所有數(shù)據(jù)都是基于查詢余票的操作,因此我們先開發(fā)這部分功能

class QueryTicket{
 constructor({ data, phoneNumber, cookie, day }) {
 //constructor代碼... 
 }
 //初始化,因?yàn)樯婕暗疆惒秸埱?,所以我們使用`async await`
  async init(){
     let ticketList = await this.handleQueryTicket() //返回查詢到的余票數(shù)組
  }
  //查詢余票的邏輯
  handleQueryTicket(){ 
  let ticketList = [] //余票數(shù)組
  let res = await this.requestTicket()
  this.times++ //計(jì)數(shù)器,記錄請求查詢多少次
  var str = res.data.replace(/\\/g, "") //格式化返回值
  var $ = cheerio.load(`<div class="main">${str}</div>`) // cheerio載入查詢接口response的html節(jié)點(diǎn)數(shù)據(jù)
  let list = $(".main").find(".b") //查找是否有余票的dom節(jié)點(diǎn)
  // 如果沒有余票,打印出請求多少次,然后返回,不執(zhí)行下面的代碼
  if (!list.length) {
   console.log(`用戶${this.phoneNumber}:無票,已進(jìn)行${this.times}次`)
   return
  }

  // 如果有余票
  list.each((idx, item) => {
   var str = $(item).html() //str這時(shí)格式是<span>21</span><span>&$x4F59;0</span>
   //最后一個(gè)span 的內(nèi)容其實(shí)"余0",也就是無票,只不過是被轉(zhuǎn)碼了而已
   //因此要在下一步對其進(jìn)行格式化
   var arr = str.split(/<span>|<\/span>|\&\#x4F59\;/).filter(item => !!item === true) 
   let data = {
    day: arr[0],
    ticketLeft: arr[1]
   }
   
   //如果是要搶指定日期的票
   if (this.day) {
   //如果有指定日期的余票
    if (parseInt(data.day) === parseInt(data.day)) {
     ticketList.push(data)
    }
   } else {
   //如果不是,則返回查詢到的所有余票
    ticketList.push(data)
   }
  })
  return ticketList
  }
   //調(diào)用查詢余票接口
  requestTicket(){
  return axios.post('http://weixin.xxxx.net/ebus/front/wxQueryController.do?BcTicketCalendar', this.postData, {
   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
   }
  })  
  }
  handleBuyTicket(){} //購票相關(guān)邏輯
  requestOrder(){}//調(diào)用購票接口
  handleInfoUser(){}//通知用戶的邏輯
  sendMSg(){} //發(fā)短信接口
}

來解釋下那行正則, cheerio 抓取到的dom是長這樣的,第一個(gè) span 內(nèi)容是日期,第二個(gè)是余票數(shù)量

 

所以我們要把它格式化變成這種數(shù)組,也就是 ticketList

 

2-3開發(fā)購票功能

首先我們在 init 方法里做個(gè)判斷,如果有余票才去購票,沒有余票購個(gè)毛

class QueryTicket{
 constructor({ data, phoneNumber, cookie, day }) {
 //constructor代碼... 
 }
 //初始化
  async init(){
  let ticketList = await this.handleQueryTicket()
  //如果有余票
  if (ticketList.length) {
  //把余票傳入購票邏輯方法,返回短信通知所需要的數(shù)據(jù)
   let resParse = await this.handleBuyTicket(ticketList)
  }
  }
  //查詢余票的邏輯
  async handleQueryTicket(){
  // 查詢余票代碼...
  }
  //調(diào)用查詢余票接口
  requestTicket(){
  //調(diào)用查詢余票接口代碼...  
  } 
  //購票相關(guān)邏輯
  async handleBuyTicket(ticketList){
  let year = new Date().getFullYear() //年份,
  let month = new Date().getMonth() + 1 //月份,拼接購票日期用得上,因?yàn)橛嗥苯涌谥环祷貛滋?
  let {
   onStationName,//起始站點(diǎn)名
   offStationName,//結(jié)束站點(diǎn)名
   lineId,//線路id
   vehTime,//發(fā)車時(shí)間
   startTime,//預(yù)計(jì)上車時(shí)間
   onStationId,//上車的站臺id
   offStationId //到站的站臺id
   } = this.data // 初始化的數(shù)據(jù)
  let station = `${onStationName}-${offStationName}` //站點(diǎn),發(fā)短信時(shí)候用到:"寶安交通局-深港產(chǎn)學(xué)研基地"
  let dateStr = ""; //車票日期
  let tickAmount = "" //總張數(shù)
  ticketList.forEach(item => {
   dateStr = dateStr + `${year}-${month}-${item.day},`
   tickAmount = tickAmount + `${item.ticketLeft}張,`
  })
  var buyTicket = {
   lineId,//線路id
   vehTime,//發(fā)車時(shí)間
   startTime,//預(yù)計(jì)上車時(shí)間
   onStationId,//上車的站點(diǎn)id
   offStationId,//目標(biāo)站點(diǎn)id
   tradePrice: '5', //金額
   saleDates: dateStr.slice(0, -1),
   payType: '2' //支付方式,微信支付
  }
  // 調(diào)用購票接口
   let data = querystring.stringify(buyTicket)
   let res = await this.requestOrder(data) //返回json數(shù)據(jù),是否購票成功等等
   //把發(fā)短信所需要數(shù)據(jù)都要傳入
  return Object.assign({}, JSON.parse(res.data), { queryParam: { dateStr, tickAmount, startTime, station } })
  }//購票相關(guān)邏輯
  //調(diào)用購票接口
  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(){} //發(fā)短信接口
}

到這里,查詢余票,購票這兩個(gè)核心操作已經(jīng)完成。

目前還剩下,如何通知用戶是否購票成功。

之前我嘗試過使用qq郵箱的smtp服務(wù),搶票成功后發(fā)送郵件通知,但是我覺得吧,并不好用,主要是我沒有打開郵箱的習(xí)慣,沒網(wǎng)也收不到,所以,并沒有采納這個(gè)方案。

加上之前我注冊過企業(yè)認(rèn)證的公眾號,騰訊云免費(fèi)送了我1000條短信通知,而且短信也比較直觀,所以我這里就安裝騰訊云的SDK,部署了一套發(fā)短信的功能。

2-4騰訊云短信的相關(guān)內(nèi)容

其實(shí)看看文檔就行了,我也是copy文檔,注意看短信單發(fā)那部分

cloud.tencent.com/document/pr…

如果跟我一樣有企業(yè)認(rèn)證的話,看快速入門這里就行了,一步步跟著操作

 

看下短信正文, {Number}

這些里面的數(shù)字是變量。

就是說短信的模板是固定的,但是里面有 {Number} 的內(nèi)容可以自定義

調(diào)用的時(shí)候,里面的數(shù)字對應(yīng)著傳過去的參數(shù)數(shù)組序號,{1}代表數(shù)組[0]參數(shù),以此類推

 

提交審核,審核一般很快就通過,也就是幾十萬毫秒吧

 

2-5 開發(fā)通知功能

class QueryTicket{
 constructor({ data, phoneNumber, cookie, day }) {
 //constructor代碼... 
 }
 //初始化
  async init(){
  let ticketList = await this.handleQueryTicket()
  //如果有余票
  if (ticketList.length) {
  //把余票傳入購票邏輯方法,返回短信通知所需要的數(shù)據(jù)
   let resParse = await this.handleBuyTicket(ticketList)
  //執(zhí)行通知邏輯
   this.handleInfoUser(resParse)
  }
  }
  
  //查詢余票的邏輯
  async handleQueryTicket(){
  // 查詢余票代碼...
  }
  //調(diào)用查詢余票接口
  requestTicket(){
  //調(diào)用查詢余票接口代碼...  
  } 
  //購票相關(guān)邏輯
  async handleBuyTicket(ticketList){
  //購票代碼...
  }
  //調(diào)用購票接口
  requestOrder(obj){
  //購票接口請求代碼...
  }
  //通知用戶的邏輯
  async handleInfoUser(parseData){
  //獲取上一步購票的response數(shù)據(jù)和我們拼接的數(shù)據(jù)
  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), //總張數(shù)
    station, //站點(diǎn)
    lineName, //巴士名稱/路線名稱
    tradePrice,//總價(jià)
    startTime,//出發(fā)時(shí)間
    phoneNumber: this.phoneNumber,//手機(jī)號
   })
   //如果發(fā)信成功,則不再進(jìn)行搶票操作
   if (res.result === 0 && res.errmsg === "OK") {
    this.setStop(true)
   } else {
   //失敗不做任何操作
    console.log(res.errmsg)
   }
  } else {
   //失敗不做任何操作
   console.log(resParse['returnInfo'])
  }    
  }
  //發(fā)短信接口
  sendMSg(){
  let { dateStr, tickAmount, station, lineName, phoneNumber, startTime, tradePrice } = obj
  var appid = 140034324; // SDK AppID 以1400開頭
  // 短信應(yīng)用 SDK AppKey
  var appkey = "asdfdsvajwienin23493nadsnzxc";
  // 短信模板 ID,需要在短信控制臺中申請
  var templateId = 7839; // NOTE: 這里的模板ID`7839`只是示例,真實(shí)的模板 ID 需要在短信控制臺中申請
  // 簽名
  var smsSign = "測試短信"; // NOTE: 簽名參數(shù)使用的是`簽名內(nèi)容`,而不是`簽名ID`。這里的簽名"騰訊云"只是示例,真實(shí)的簽名需要在短信控制臺申請
  // 實(shí)例化 QcloudSms
  var qcloudsms = QcloudSms(appid, appkey);
  var ssender = qcloudsms.SmsSingleSender();
  // 這里的params就是短信里面可以自定義的內(nèi)容,也就是填入{1}{2}..的內(nèi)容
  var 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)
    }
   });
  })
  } 
}

如果發(fā)信成功,返回 result:0

 

到這里,大部分需求已經(jīng)完成了,還剩下一個(gè)定時(shí)任務(wù)

2-6 定時(shí)任務(wù)

也聲明一個(gè)類,這里我們用到的是 schedule

// 定時(shí)任務(wù)
class SetInter {
 constructor({ timer, fn }) {
  this.timer = timer // 每幾秒執(zhí)行
  this.fn = fn //執(zhí)行的回調(diào)
  this.rule = new schedule.RecurrenceRule(); //實(shí)例化一個(gè)對象
  this.rule.second = this.setRule() // 調(diào)用原型方法,schedule的語法而已
  this.init()
 }
 setRule() {
  let rule = [];
  let i = 1;
  while (i < 60) {
   rule.push(i)
   i += this.timer
  }
  return rule //假設(shè)傳入的timer為5,則表示定時(shí)任務(wù)每5秒執(zhí)行一次
  // [1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56] 
 }
 init() {
  schedule.scheduleJob(this.rule, () => {
   this.fn() // 定時(shí)調(diào)用傳入的回調(diào)方法
  });
 }
}

2-7 多個(gè)用戶搶票

假設(shè)我們有兩個(gè)用戶要搶票,所以定義兩個(gè)obj,實(shí)例化下 QueryTicket 類

data: { //用戶1
  lineId: 111130,
  vehTime: 0722,
  startTime: 0751,
  onStationId: 564492,
  offStationId: 17990,
  onStationName: '寶安交通運(yùn)輸局③',
  offStationName: "深港產(chǎn)學(xué)研基地",
  tradePrice: 0,
  saleDates: '',
  beginDate: '',
 },
 phoneNumber: 123123123,
 cookie: 'JSESSIONID=TESTCOOKIE',
 day: "17"
}
var 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: "" 
}
var ticket = new QueryTicket(obj) //用戶1
var ticket2 = new QueryTicket(obj2) //用戶2

new SetInter({
 timer: 1, //每秒執(zhí)行一次,建議5秒,不然怕被ip拉黑,我這里只是為了方便下面截圖
 fn: function () {
  [ticket,ticket2].map(item => { //同時(shí)進(jìn)行兩個(gè)用戶的搶票
   if (!item.getStop()) { //調(diào)用實(shí)例的原型方法,判斷是否停止搶票,如果沒有則繼續(xù)搶
    item.init()
   } else { // 如果搶到票了,則不繼續(xù)搶票
    console.log('stop')
   }
  })
 }
})

node index.js 運(yùn)行下,跑起來了

 

如果他搶到票的話,我就會收到短信通知:

 

打開手機(jī),看下訂單信息

 

搞定,收工

寫在最后

其實(shí)可以在此基礎(chǔ)上還能添加更多功能,比如直接抓取登錄接口獲取cookie,指定路線搶票,還有錯(cuò)誤處理啊啥的

因?yàn)檫@個(gè)只是我個(gè)人使用,所以只有這點(diǎn)功能就足夠了。

如果想把它做成一個(gè)完整的項(xiàng)目,建議使用ts加持 ,關(guān)于ts我推薦閱讀這篇JD前端寫的文章

juejin.im/post/5d8efe…

希望各位能有所收獲

總結(jié)

以上所述是小編給大家介紹的Node.js 實(shí)現(xiàn)搶票小工具 & 短信通知提醒功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!

相關(guān)文章

  • Node配合WebSocket做多文件下載以及進(jìn)度回傳

    Node配合WebSocket做多文件下載以及進(jìn)度回傳

    這篇文章主要介紹了Node配合WebSocket做多文件下載以及進(jìn)度回傳功能,本文通過實(shí)例代碼效果截圖給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2019-11-11
  • window10系統(tǒng)下nvm詳細(xì)安裝步驟以及使用

    window10系統(tǒng)下nvm詳細(xì)安裝步驟以及使用

    nvm可以管理不同版本的node和npm,可以簡單操作node版本的切換、安裝、查看等,下面這篇文章主要給大家介紹了關(guān)于window10系統(tǒng)下nvm詳細(xì)安裝步驟以及使用的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • Sequelize中用group by進(jìn)行分組聚合查詢

    Sequelize中用group by進(jìn)行分組聚合查詢

    大家都知道在SQL查詢中,分組查詢是較常用的一種查詢方式。分組查詢是指通過GROUP BY關(guān)鍵字,將查詢結(jié)果按照一個(gè)或多個(gè)字段進(jìn)行分組,分組時(shí)字段值相同的會被分為一組。在Node.js基于Sequelize的ORM框架中,同樣支持分組查詢,使用非常簡單方便。下面來看看詳細(xì)的介紹。
    2016-12-12
  • 進(jìn)階之初探nodeJS

    進(jìn)階之初探nodeJS

    本文主要介紹了nodeJS的相關(guān)知識。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-01-01
  • node.JS路徑解析之PATH模塊使用方法詳解

    node.JS路徑解析之PATH模塊使用方法詳解

    path模塊包含一系列處理和轉(zhuǎn)換文件路徑的工具集,通過 require('path') 可用來訪問這個(gè)模塊。本文將詳細(xì)介紹path模塊
    2020-02-02
  • npm使用淘寶鏡像及切換回官方源的操作命令

    npm使用淘寶鏡像及切換回官方源的操作命令

    這篇文章主要給大家介紹了npm使用淘寶鏡像及切換回官方源的操作命令,文中給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-02-02
  • Node.js?queryString?解析和格式化網(wǎng)址查詢字符串工具使用

    Node.js?queryString?解析和格式化網(wǎng)址查詢字符串工具使用

    這篇文章主要為大家介紹了Node.js?queryString?解析和格式化網(wǎng)址查詢字符串工具使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • nodejs版本管理工具nvm的安裝與使用小結(jié)

    nodejs版本管理工具nvm的安裝與使用小結(jié)

    在項(xiàng)目開發(fā)過程中,使用到vue框架技術(shù),需要安裝node下載項(xiàng)目依賴,本文主要介紹了nodejs版本管理工具nvm的安裝與使用小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • 實(shí)例詳解Nodejs 保存 payload 發(fā)送過來的文件

    實(shí)例詳解Nodejs 保存 payload 發(fā)送過來的文件

    這篇文章主要介紹了實(shí)例詳解Nodejs 保存 payload 發(fā)送過來的文件 的相關(guān)資料,需要的朋友可以參考下
    2016-01-01
  • Nginx設(shè)置為Node.js的前端服務(wù)器方法總結(jié)

    Nginx設(shè)置為Node.js的前端服務(wù)器方法總結(jié)

    在本篇文章中小編給大家分享了關(guān)于Nginx設(shè)置為Node.js的前端服務(wù)器的方法和實(shí)例,需要的朋友們學(xué)習(xí)下。
    2019-03-03

最新評論