【背景】
快过年了,我妈一个电话打过来叫我给他买火车票,我到12306一查,硬座和硬卧基本没有了,高铁又太贵.
最后只抢了3张无座票,但是我妈说能不能买有座位的啊,我说没有了啊,我妈:你过两天再帮我看看。我:...
为了帮老妈抢到有座的票,后来用了360抢票插件,还用了网上的一个别人用c#写的客户端来抢票,妈的,用了两三天都没用。
最后还是打算自己用node写一个,当时我的想法就是写个简单的,能用就行。
所以,思路如下:
用node写一个爬虫,每过一分钟就爬取12306,查询某一辆火车是否还有余票,有余票就给我发一封邮件,提醒我有余票了,然后我立马登录12306改签。
这个思路的有两点前提,第一、要自己提前确定好想买哪一辆火车,包括:火车车次,日期。第二、自己要经常在电脑前,只要一来邮件就去12306买票,这对于程序猿来说已经满足了。
【代码实现】
要想实现我的想法,运用到了2个node库:nodemailer和node-schedule,分别实现邮件和定时执行功能。
因为12306是https协议的,所以node的http模块还是不行,这里可以用node的https模块。
当然12306还需要有浏览器证书,我代码里已经有了,大家下下来就可以用。
代码:
var https = require('https');
var fs = require('fs');
var ca = fs.readFileSync('./cert/srca.cer.pem');
var nodemailer = require('nodemailer');
var schedule = require('node-schedule');
var config = {
time:'2017-01-21',//日期格式必须是这样
from_station:'BJP',//始发站车站代码,这里是北京北
end_station:'XMS',//厦门
train_num:'K571'//车次
your_mail:'****@163.com',//你自己的邮箱,我这里用的是163邮箱,如果你要改其他类型的邮箱的话,那请你修改transporter里的服务器信息
mail_pass:'****'//放心写吧
};
var yz_temp = '',yw_temp = '';//保存余票状态
function queryTickets(config){
var options = {
hostname: 'kyfw.12306.cn',//
path: '/otn/leftTicket/queryA?leftTicketDTO.train_date='+config.time+'&leftTicketDTO.from_station='+config.from_station+'&leftTicketDTO.to_station='+config.end_station+'&purpose_codes=ADULT',
ca:[ca]//证书
};
var req = https.get(options, function(res){
var data = '';
var transporter = nodemailer.createTransport({
host: "smtp.163.com",//邮箱的服务器地址,如果你要换其他类型邮箱(如QQ)的话,你要去找他们对应的服务器,
secureConnection: true,
port:465,//端口,这些都是163给定的,自己到网上查163邮箱的服务器信息
auth: {
user: config.your_mail,//邮箱账号
pass: config.mail_pass,//邮箱密码
}
});
res.on('data',function(buff){
data += buff;//查询结果(JSON格式)
});
res.on('end',function(){
// console.log('res',data);
var jsonData = JSON.parse(data).data;
for(var i=0;i<jsonData.length;i++){
var cur = jsonData[i];
if(cur.queryLeftNewDTO.station_train_code==config.train_num){
// console.log(cur);
var yz = cur.queryLeftNewDTO.yz_num;//硬座数目
var yw = cur.queryLeftNewDTO.yw_num;//硬卧数目
var trainNum = cur.queryLeftNewDTO.station_train_code;//车次
console.log('硬座',yz);
console.log('硬卧',yw);
if(yz!='无'&&yz!='--'||yw!='无'&&yw!='--'){
if(yw_temp == yw && yz_temp == yz){//当余票状态发生改变的时候就不发送邮件
console.log('状态没改变,不重复发邮件');
return;
}
var mailOptions = {
from: config.your_mail, // 发件邮箱地址
to: config.your_mail, // 收件邮箱地址,可以和发件邮箱一样
subject: trainNum+'有票啦,硬座:'+yz+',硬卧:'+yw, // 邮件标题
text: trainNum+'有票啦\n'+'时间是'+cur.queryLeftNewDTO.start_train_date+',\n出发时间:'+cur.queryLeftNewDTO.start_time+',\n到达时间:'+cur.queryLeftNewDTO.arrive_time+',\n历时:'+cur.queryLeftNewDTO.lishi+',\n始发站:'+cur.queryLeftNewDTO.from_station_name+',\n到达:'+cur.queryLeftNewDTO.to_station_name, // 邮件内容
}; // 发邮件部分
transporter.sendMail(mailOptions, function(error, info){
if(error){
return console.log(error);
}
console.log('Message sent: ' + info.response);
yw_temp = yw;//保存当前列车的余票数量
yz_temp = yz;
});
}else{
console.log('硬座/硬卧无票');
} break;
}
}
// fs.writeFile('./train.json',data);
})
}); req.on('error', function(err){
console.error(err.code);
});
}
var rule = new schedule.RecurrenceRule();
rule.second = [0];
schedule.scheduleJob(rule, function(){
queryTickets(config);
console.log('scheduleCronstyle:' + new Date());
});
下面说下上述代码中的config里面的参数如何找到:
譬如我要找北京到厦门的火车:
首先进入12306余票查询页面:
点击查询之后控制台出现以下信息:
看最后一个点击打开:
看到红框里的内容就是config里面需要配置的选项了。
然后运行node main.js,然后一直放在那运行(可以放到自己的服务器上去运行)
运行结果:
总结一下,我这个如果想用这个买票,你只要配置config,替换里面的邮箱和密码(你自己的邮箱),这样就会收到邮件通知了。
目前我已经用这个把之前买的3张无座全都改签为硬座票了(因为有人要退票啊,哈哈)
大家最好用163邮箱和163的手机客户端吧,通知及时,一有邮件我的手机就会震动提示。
【更新于2017-4-1】
已经解决不能请求成功导致查询不到余票信息的问题,同时修改了若干错误,现在已经可以正常使用。
现在的运行结果:
查询结果:
代码地址:node_12306
(希望大牛勿喷,多多指点,有空会完善功能。)
史上最“脑残”的“抢火车票”程序(node.js版)的更多相关文章
-
在 Azure 中的 Linux VM 上创建 MongoDB、Express、AngularJS 和 Node.js (MEAN) 堆栈
本教程介绍如何在 Azure 中的 Linux VM 上实现 MongoDB.Express.AngularJS 和 Node.js (MEAN) 堆栈. 通过创建的 MEAN 堆栈,可以在数据库中添 ...
-
.Net魔法堂:史上最全的ActiveX开发教程——ActiveX与JS间交互篇
一.前言 经过上几篇的学习,现在我们已经掌握了ActiveX的整个开发过程,但要发挥ActiveX的真正威力,必须依靠JS.下面一起来学习吧! 二.JS调用ActiveX方法 只需在UserContr ...
-
【效率工具】史上最好用的SSH一键登录脚本,第三版更新!
说明 时隔一周,GotoSSH又迎来了一次重大更新,让这个史诗级的shell工具变得更加丝般顺滑了~ 这次的主要更新是对自定义全局命令以及自定义属性的支持,让设置更加灵活,此外,对各个细节进行了调整, ...
-
史上最全的web前端开发程序员学习清单!
今天为什么要给大家分享这篇文章呢,我发现最近来学前端的特别多,群里面整天都有人问:前端好找工作吗?前端要怎么学啊?前端工资怎么样?前端XX,前端XXX,虽然我回答过无数次这种问题了,但是问这个的还是有 ...
-
.Net魔法堂:史上最全的ActiveX开发教程——自动更新、卸载篇
一.前言 B/S模式的特点之一,客户端版本升级相对简单.快捷,适合产品的快速迭代.而ActiveX组件的自动更新同样也继承了这一优点.下面我们一起来了解吧! 二.二话不说更新ActiveX 1. 设置 ...
-
史上最详细的XGBoost实战
史上最详细的XGBoost实战 0. 环境介绍 Python 版 本: 3.6.2 操作系统 : Windows 集成开发环境: PyCharm 1. 安装Python环境 安装Python 首先,我 ...
-
Node.js~在linux上的部署~外网不能访问node.js网站的解决方法
这是上一篇node.js部署到linux上的后续文章,当我们安装完node.js之后,建立了sailsjs的网站,然后在外面电脑上无法访问这个网站,这个问题我们如何去解决? 解决思路: 查看linux ...
-
深入浅出Node.js(上)
(一):什么是Node.js Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS创始人Ryan Dalh加盟 ...
-
脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?
本文引用了“帅地”发表于公众号苦逼的码农的技术分享. 1.引言 搞网络通信应用开发的程序员,可能会经常听到外网IP(即互联网IP地址)和内网IP(即局域网IP地址),但他们的区别是什么?又有什么关系呢 ...
随机推荐
-
Xshell5 里桌面显示数据调大!!!
今天告诉大家一个好用的技巧, 在Xshell5下工作,屏幕上很容易积攒数据量,尤其是编译的时候,(当然你编译的时候可以重定向到一个文件中,也可以只重定向编译错误的信息): 这个时候,你想观看之前的编译 ...
-
Nancy之Forms authentication的简单使用
一.前言 想必大家或多或少都听过微软推出的ASP.NET Identity技术,可以简单的认为就是一种授权的实现 很巧的是,Nancy中也有与之相类似的技术Authentication,这两者之间都用 ...
-
ie8解决F12问题
工作中,突然电脑上的ie8按F12掉不出来了,一直显示最小化.于是在网上找了很多方法,按这种方法可以解决问题. 1.cmd+r,输入regedit,调出 注册表编辑器. 2.HKEY_CURRENT_ ...
-
Eclipse Java EE 创建 Dynamic Web Project
1. 创建一个web工程,此处用eclipse创建(如果对创建web工程很熟悉,可以不看的,本文目的是做一个记录) 1) 打开新建工程对话框,选择Dynamic web Proje ...
-
OD: File Vulnerabilities &; Protocols &; Fuzz
IE.Office 等软件有个共同点,即用文件作为程序的主要输入,但攻击者往往会挑战程序员的假定和假设. 文件格式 Fuzz 就是利用畸形文件测试软件的稳健性,其流程一般包括: * 以一个正常文件作为 ...
-
symfony框架在中国移动cmwap网络下访问的问题
最近用symfony框架给手机app做后台,发现在中国移动cmwap网络下会出现问题,所有请求都路由到根路径了 左图为原始$_SERVER对象,右图为$request->server对象由于re ...
-
Flask对请求的处理
由http://www.cnblogs.com/steinliber/p/5133386.html 中可得服务器会把environ和start_response发送给Flask的实例app,返回的是a ...
-
ubuntu卸载vmware
下面方法摘抄网上方法,经过证实好使 lsmod——显示已载入系统的模块 ps aux : 显示其他用户启动的进程(a) 查看系统中属于自己的进程(x) 启动这个进程的用户和它启动的 ...
-
Robotium源码分析之运行原理
从上一章<Robotium源码分析之Instrumentation进阶>中我们了解到了Robotium所基于的Instrumentation的一些进阶基础,比如它注入事件的原理等,但Rob ...
-
Java实现压缩文件与解压缩文件
由于工作需要,需要将zip的压缩文件进行解压,经过调查发现,存在两个开源的工具包,一个是Apache的ant工具包,另一个就是Java api自带的工具包:但是Java自带的工具包存在问题:如果压缩或 ...