您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關(guān)Node.js如何實(shí)現(xiàn)搶票小工具&短信通知提醒功能的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來(lái)看看吧。
獲取接口信息
1.查看頁(yè)面結(jié)構(gòu)
這個(gè)就是訂票頁(yè)面,顯示當(dāng)前月的車票情況,根據(jù)圖示,紅色為已滿,綠色為已購(gòu),灰色為不可選
如果是可選就是白色的小方塊,并且在下面顯示余票,如下圖所示:
我們打算這么做,
定時(shí)抓取返回的接口信息
根據(jù)接口返回值判斷是否有余票
好,審查下源代碼看下接口信息,等等,微信瀏覽器沒辦法審查源代碼,于是
2.使用chrome調(diào)試微信公眾號(hào)網(wǎng)頁(yè)頁(yè)面
首先面臨個(gè)問題,如果直接copy公眾號(hào)網(wǎng)頁(yè)Url在chrome打開的話,就會(huì)顯示這個(gè)畫面,他被302重定向到了這個(gè)頁(yè)面,所以是行不通的,只有獲取OAuth3.0授權(quán)才能進(jìn)去
所以我們得先通過抓包工具,知道手機(jī)訪問微信公眾號(hào)網(wǎng)頁(yè)的時(shí)候,需要帶什么信息過去,這時(shí)候我們就得借助抓包工具,因?yàn)槲译娔X是Mac,用不了 Fiddler
,我用的是 Charles
花瓶,就是下面這位仁兄
借助這個(gè)工具,我們只需3步就可以輕松搞定手機(jī)數(shù)據(jù)抓包:
獲取本機(jī)IP地址和端口
設(shè)置代理手機(jī)上網(wǎng)
依次執(zhí)行上面兩步
2-1 獲取本機(jī)IP地址和端口
第一步,找到端口號(hào),一般默認(rèn)是8088,但是為了確認(rèn)可以打開 Proxy
/ Proxy Setting
看下,哦原來(lái)我之前設(shè)置成了8888
然后找到 Charles
的 help
/ Local IP Address
,點(diǎn)擊它就會(huì)看到自己的本機(jī)地址,找到本機(jī)地址記下來(lái),然后進(jìn)行下一步
2-2設(shè)置代理手機(jī)上網(wǎng)
首先保證手機(jī)跟電腦連接的是同一個(gè)wifi,然后在wifi設(shè)置那里會(huì)有設(shè)置代理信息,比如我的猴米...不對(duì),小米9手機(jī)!設(shè)置如下:
輸入上一步獲取主機(jī)名,端口號(hào)就ok了
輸入完成,點(diǎn)擊確定后。 Charles
就會(huì)彈出一個(gè)對(duì)話框,問你是否同意接入代理,點(diǎn)擊確定allow就行了。
2-3 用手機(jī)訪問目標(biāo)網(wǎng)頁(yè)
我們用手機(jī)訪問微信公眾號(hào)【深圳x出行】進(jìn)入到搶票頁(yè)面后,發(fā)現(xiàn) Charles
已經(jīng)成功抓包到了網(wǎng)頁(yè)信息,當(dāng)我們進(jìn)入這個(gè)搶票頁(yè)面的時(shí)候,他會(huì)發(fā)起兩個(gè)請(qǐng)求,一個(gè)是獲取document文檔內(nèi)容,一個(gè)post請(qǐng)求獲取票務(wù)信息。
仔細(xì)分析了下,大概明白了業(yè)務(wù)邏輯:
整個(gè)項(xiàng)目技術(shù)站是java+jsp,傳統(tǒng)寫法,用戶身份驗(yàn)證主要是cookie+session方案,前端這一塊主要是使用 jQuery
。
當(dāng)用戶進(jìn)入頁(yè)面的時(shí)候,會(huì)攜帶查詢參數(shù),如起始站點(diǎn),時(shí)間,車次等信息和cookie請(qǐng)求document文檔, 也就是圈起來(lái)的這一塊,
而我們想要的核心內(nèi)容:日歷表,一開始是不顯示的
因?yàn)檫€要在請(qǐng)求一次
第二次請(qǐng)求,攜帶cookie和以上的查詢參數(shù)發(fā)起一個(gè)post請(qǐng)求,獲取當(dāng)月的車票信息,也就是日歷表內(nèi)容
下面這個(gè)是請(qǐng)求當(dāng)月票務(wù)信息,然而發(fā)現(xiàn)他返回的是一堆html節(jié)點(diǎn)
好吧...估計(jì)是獲取到之后直接 append
到 div
里面的,然后渲染生成日歷表內(nèi)容
接著在手機(jī)上操作,選擇兩個(gè)日期,然后點(diǎn)擊下單,發(fā)送購(gòu)票請(qǐng)求,拉取購(gòu)票接口,我們看下購(gòu)票接口的請(qǐng)求和返回內(nèi)容:
看下request 內(nèi)容,根據(jù)字段的意思大概明白是線路,時(shí)間,以及車票金額,還有支付方式
在看看返回的內(nèi)容:返回一個(gè)json字符串?dāng)?shù)據(jù),里面大概涵蓋了下單的成功返回碼,時(shí)間,id號(hào)等等信息
2-4 記錄所需要的信息內(nèi)容
根據(jù)上面的分析,總結(jié)下內(nèi)容: 整個(gè)項(xiàng)目用戶身份驗(yàn)證是使用 cookie
和 session
方案,請(qǐng)求數(shù)據(jù)用的是 form data
方式,請(qǐng)求字段啥的我們也都清楚,唯獨(dú)有一點(diǎn),就是請(qǐng)求余票的時(shí)候,返回的是html節(jié)點(diǎn)代碼,而不是我們預(yù)期的json數(shù)據(jù),這樣就有個(gè)麻煩,我們沒辦法一目了然的明白他余票的時(shí)候是如何顯示的
所以我們只能通過 chrome
進(jìn)行調(diào)試,才能得出他是如何判斷余票的。
我們找個(gè)記事本,記錄下信息,記錄的內(nèi)容有:
請(qǐng)求余票接口和購(gòu)票接口的 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抓包本地請(qǐng)求
因?yàn)槲覀円勋@取到的cookie填入到chrome里面,以我們的用戶身份去訪問網(wǎng)頁(yè),所以我們需要在請(qǐng)求目標(biāo)地址的時(shí)候,改包修改cookie
首先我們需要開啟 macOS Proxy
,抓包我們的http請(qǐng)求
打開chrome訪問目標(biāo)網(wǎng)址,我們可以看到 Charles
上已經(jīng)抓包到了我們?cè)L問的目標(biāo)url地址,然后給目標(biāo)url地址打上斷點(diǎn),方便調(diào)試
然后再次訪問,這時(shí)候斷點(diǎn)就生效了,彈出一個(gè)tab名為 break points
,可以看到之所以我們還是不能訪問到目標(biāo)網(wǎng)址,是因?yàn)?sessionId
不對(duì),所以我們把抓取到的 cookie
在填入到里面,點(diǎn)擊 execute
這時(shí)候,能夠正確跳到目標(biāo)頁(yè)面了。
大概看了下他整體布局,和 jQuery
代碼 CSS
代碼,特別是日歷表那一塊
審查了下元素發(fā)現(xiàn):
小方塊的結(jié)構(gòu)為:
<td class="b"> <span>這里為日期</span> <span>如果有余票則顯示余票數(shù)量</span> </td>
td的樣式名為 a
代表不可選
樣式名為 e
代表已滿
樣式名為 d
代表已購(gòu)
樣式名為 b
則是我們要找的,代表可選,也就是有余票
到這一步,整個(gè)購(gòu)票流程就清楚了
到時(shí)候我們通過Node.js請(qǐng)求的時(shí)候,處理返回?cái)?shù)據(jù),用正則去判斷是否有余票的class名 b
,有余票的話,在獲取div里面的余票數(shù)量?jī)?nèi)容就Ok了
2.Node.js 請(qǐng)求目標(biāo)接口
2-1 分析需要開發(fā)的功能點(diǎn)
寫代碼之前我們需要想好功能點(diǎn),我們需要什么功能:
請(qǐng)求余票接口
定時(shí)請(qǐng)求任務(wù)
有余票則自動(dòng)請(qǐng)求購(gòu)票接口下訂單
調(diào)用騰訊云短信api接口發(fā)送短信通知
多個(gè)用戶搶票功能
搶某個(gè)日期的票
首先 mkdir ticket
創(chuàng)建名為ticket的文件夾,接著 cd ticket
進(jìn)入文件夾 npm init
一路瞎幾把回車也無(wú)妨。 下面開始安裝依賴,根據(jù)上面的功能需求,我們大概需要:
1.請(qǐng)求工具,這里看個(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ā)請(qǐng)求余票接口
接著 touch index.js 創(chuàng)建核心js文件,開始編碼:
首先引入所有依賴
const axios = require('axios') const querystring = require("querystring"); //序列化對(duì)象,用qs也行,都一樣 var QcloudSms = require("qcloudsms_js"); var cheerio = require('cheerio'); var schedule = require('node-schedule');
然后我們先定義請(qǐng)求參數(shù),來(lái)一個(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ī)號(hào),接收短信的手機(jī)號(hào) cookie: 'JSESSIONID=TESTCOOKIE', // 抓取到的cookie day: "17" //定17號(hào)的票,這個(gè)主要是用于搶指定日期的票,滯空則為搶當(dāng)月所有余票 }
接著聲明一個(gè)名為 queryTicket 的類,為啥要用類呢,因?yàn)榛诘谖鍌€(gè)需求點(diǎn),多個(gè)用戶搶票的時(shí)候,我們分別 new 一下就行了,
同時(shí)我們希望能夠記錄請(qǐng)求余票的次數(shù),和當(dāng)搶到票后自動(dòng)停止查詢余票得操作,所以給他加上個(gè)計(jì)數(shù)變量 times 和是否停止的變量,布爾值 stop
編寫代碼:
class QueryTicket{ /** *Creates an instance of QueryTicket. * @param {Object} { data, phoneNumber, cookie, day } * @param data {Object} 請(qǐng)求余票接口的requery參數(shù) * @param phoneNumber {Number} 用戶手機(jī)號(hào),短信需要用到 * @param cookie {String} cookie信息 * @params day {String} 某日的票,如'18' * @memberof QueryTicket 請(qǐng)求余票接口 */ 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(){} //購(gòu)票相關(guān)邏輯 requestOrder(){}//調(diào)用購(gòu)票接口 handleInfoUser(){}//通知用戶的邏輯 sendMSg(){} //發(fā)短信接口 }
所有數(shù)據(jù)都是基于查詢余票的操作,因此我們先開發(fā)這部分功能
class QueryTicket{ constructor({ data, phoneNumber, cookie, day }) { //constructor代碼... } //初始化,因?yàn)樯婕暗疆惒秸?qǐng)求,所以我們使用`async await` async init(){ let ticketList = await this.handleQueryTicket() //返回查詢到的余票數(shù)組 } //查詢余票的邏輯 handleQueryTicket(){ let ticketList = [] //余票數(shù)組 let res = await this.requestTicket() this.times++ //計(jì)數(shù)器,記錄請(qǐng)求查詢多少次 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) // 如果沒有余票,打印出請(qǐng)求多少次,然后返回,不執(zhí)行下面的代碼 if (!list.length) { console.log(`用戶${this.phoneNumber}:無(wú)票,已進(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",也就是無(wú)票,只不過是被轉(zhuǎn)碼了而已 //因此要在下一步對(duì)其進(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(){} //購(gòu)票相關(guān)邏輯 requestOrder(){}//調(diào)用購(gòu)票接口 handleInfoUser(){}//通知用戶的邏輯 sendMSg(){} //發(fā)短信接口 }
來(lái)解釋下那行正則, cheerio 抓取到的dom是長(zhǎng)這樣的,第一個(gè) span 內(nèi)容是日期,第二個(gè)是余票數(shù)量
所以我們要把它格式化變成這種數(shù)組,也就是 ticketList
2-3開發(fā)購(gòu)票功能
首先我們?cè)?init 方法里做個(gè)判斷,如果有余票才去購(gòu)票,沒有余票購(gòu)個(gè)毛
class QueryTicket{ constructor({ data, phoneNumber, cookie, day }) { //constructor代碼... } //初始化 async init(){ let ticketList = await this.handleQueryTicket() //如果有余票 if (ticketList.length) { //把余票傳入購(gòu)票邏輯方法,返回短信通知所需要的數(shù)據(jù) let resParse = await this.handleBuyTicket(ticketList) } } //查詢余票的邏輯 async handleQueryTicket(){ // 查詢余票代碼... } //調(diào)用查詢余票接口 requestTicket(){ //調(diào)用查詢余票接口代碼... } //購(gòu)票相關(guān)邏輯 async handleBuyTicket(ticketList){ let year = new Date().getFullYear() //年份, let month = new Date().getMonth() + 1 //月份,拼接購(gòu)票日期用得上,因?yàn)橛嗥苯涌谥环祷貛滋?hào) let { onStationName,//起始站點(diǎn)名 offStationName,//結(jié)束站點(diǎn)名 lineId,//線路id vehTime,//發(fā)車時(shí)間 startTime,//預(yù)計(jì)上車時(shí)間 onStationId,//上車的站臺(tái)id offStationId //到站的站臺(tái)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)用購(gòu)票接口 let data = querystring.stringify(buyTicket) let res = await this.requestOrder(data) //返回json數(shù)據(jù),是否購(gòu)票成功等等 //把發(fā)短信所需要數(shù)據(jù)都要傳入 return Object.assign({}, JSON.parse(res.data), { queryParam: { dateStr, tickAmount, startTime, station } }) }//購(gòu)票相關(guān)邏輯 //調(diào)用購(gòu)票接口 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òu)票這兩個(gè)核心操作已經(jīng)完成。
目前還剩下,如何通知用戶是否購(gòu)票成功。
之前我嘗試過使用qq郵箱的smtp服務(wù),搶票成功后發(fā)送郵件通知,但是我覺得吧,并不好用,主要是我沒有打開郵箱的習(xí)慣,沒網(wǎng)也收不到,所以,并沒有采納這個(gè)方案。
加上之前我注冊(cè)過企業(yè)認(rèn)證的公眾號(hào),騰訊云免費(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ù)字對(duì)應(yīng)著傳過去的參數(shù)數(shù)組序號(hào),{1}代表數(shù)組[0]參數(shù),以此類推
提交審核,審核一般很快就通過,也就是幾十萬(wàn)毫秒吧
2-5 開發(fā)通知功能
class QueryTicket{ constructor({ data, phoneNumber, cookie, day }) { //constructor代碼... } //初始化 async init(){ let ticketList = await this.handleQueryTicket() //如果有余票 if (ticketList.length) { //把余票傳入購(gòu)票邏輯方法,返回短信通知所需要的數(shù)據(jù) let resParse = await this.handleBuyTicket(ticketList) //執(zhí)行通知邏輯 this.handleInfoUser(resParse) } } //查詢余票的邏輯 async handleQueryTicket(){ // 查詢余票代碼... } //調(diào)用查詢余票接口 requestTicket(){ //調(diào)用查詢余票接口代碼... } //購(gòu)票相關(guān)邏輯 async handleBuyTicket(ticketList){ //購(gòu)票代碼... } //調(diào)用購(gòu)票接口 requestOrder(obj){ //購(gòu)票接口請(qǐng)求代碼... } //通知用戶的邏輯 async handleInfoUser(parseData){ //獲取上一步購(gòu)票的response數(shù)據(jù)和我們拼接的數(shù)據(jù) let { returnCode, returnData: { main: { lineName, tradePrice } }, queryParam: { dateStr, tickAmount, startTime, station } } = parseData //如果購(gòu)票成功,則返回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ī)號(hào) }) //如果發(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,需要在短信控制臺(tái)中申請(qǐng) var templateId = 7839; // NOTE: 這里的模板ID`7839`只是示例,真實(shí)的模板 ID 需要在短信控制臺(tái)中申請(qǐng) // 簽名 var smsSign = "測(cè)試短信"; // NOTE: 簽名參數(shù)使用的是`簽名內(nèi)容`,而不是`簽名ID`。這里的簽名"騰訊云"只是示例,真實(shí)的簽名需要在短信控制臺(tái)申請(qǐng) // 實(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來(lái)封裝下異步操作 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è)對(duì)象 this.rule.second = this.setRule() // 調(diào)用原型方法,schedule的語(yǔ)法而已 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: '百度國(guó)際大廈', 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)行下,跑起來(lái)了
如果他搶到票的話,我就會(huì)收到短信通知:
打開手機(jī),看下訂單信息
搞定,收工
感謝各位的閱讀!關(guān)于“Node.js如何實(shí)現(xiàn)搶票小工具&短信通知提醒功能”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。