12306 余票检测软件
2020-09-23 本文已影响0人
luacoding
根据日期,始发站,终点站,车次等信息检测 12306 是否有余票
一、实现方式
给 12306 购票网页注入脚本,脚本模拟请求,解析参数,获取最终的余票信息
余票信息通过接口信息通知服务端
二、脚本解析
1.获取所有车站名称对应的MAP
station_names
是12306网站定义的全部变量,注入的脚本可以直接使用。
这个MAP
服务于获取余票接口的参数
代码如下:
function getStationMap() {
const arr = station_names.split("@");
const ret = {};
arr.forEach((item) => {
if (item) {
ret[item.split("|")[1]] = item.split("|")[2];
}
});
return ret;
}
结果如下:

2.请求接口,获取混淆的余票信息
参数说明:
- date:日期
- from:始发站
- to:目的地
- filter:筛选条件
代码如下:
function getList({ date, from, to, filter = [] }) {
const station = getStationMap();
get(
`https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=${date}&leftTicketDTO.from_station=${station[from]}&leftTicketDTO.to_station=${station[to]}&purpose_codes=ADULT`
)
.then((res) => {
console.log(res);
})
.catch((e) => {
console.log("请求失败2:", e);
});
}
getList({
date: "2020-10-05",
from: "九江",
to: "武汉",
filter: [
{ site: "硬卧二等卧", type: "K" },
{ site: "二等座", type: "G" },
],
});
接口获取到的 res
是一个混淆过的json
,我们需要额外的函数处理。
3.数据解码
解码函数代码如下:
function cr(cQ, cS, filter) {
var cP = [];
for (var cO = 0; cO < cQ.length; cO++) {
var cT = [];
var cN = cQ[cO].split("|");
cT.secretStr = cN[0];
cT.buttonTextInfo = cN[1];
var cR = [];
cR.train_no = cN[2];
cR.station_train_code = cN[3];
cR.start_station_telecode = cN[4];
cR.end_station_telecode = cN[5];
cR.from_station_telecode = cN[6];
cR.to_station_telecode = cN[7];
cR.start_time = cN[8];
cR.arrive_time = cN[9];
cR.lishi = cN[10];
cR.canWebBuy = cN[11];
cR.yp_info = cN[12];
cR.start_train_date = cN[13];
cR.train_seat_feature = cN[14];
cR.location_code = cN[15];
cR.from_station_no = cN[16];
cR.to_station_no = cN[17];
cR.is_support_card = cN[18];
cR.controlled_train_flag = cN[19];
cR.gg_num = cN[20] ? cN[20] : "--";
cR.gr_num = cN[21] ? cN[21] : "--";
cR.qt_num = cN[22] ? cN[22] : "--";
cR["软卧一等卧"] = cN[23] ? cN[23] : "--";
cR["软座"] = cN[24] ? cN[24] : "--";
cR.tz_num = cN[25] ? cN[25] : "--";
cR["无座"] = cN[26] ? cN[26] : "--";
cR.yb_num = cN[27] ? cN[27] : "--";
cR["硬卧二等卧"] = cN[28] ? cN[28] : "--";
cR["硬座"] = cN[29] ? cN[29] : "--";
cR["二等座"] = cN[30] ? cN[30] : "--";
cR["一等座"] = cN[31] ? cN[31] : "--";
cR["商务座特等座"] = cN[32] ? cN[32] : "--";
cR.srrb_num = cN[33] ? cN[33] : "--";
cR.yp_ex = cN[34];
cR.seat_types = cN[35];
cR.exchange_train_flag = cN[36];
cR.houbu_train_flag = cN[37];
cR.houbu_seat_limit = cN[38];
if (cN.length > 46) {
cR.dw_flag = cN[46];
}
cR.from_station_name = cS[cN[6]];
cR.to_station_name = cS[cN[7]];
cT.queryLeftNewDTO = cR;
cP.push(cT);
}
return cP
.map((item) => {
const { queryLeftNewDTO } = item;
const {
from_station_name,
to_station_name,
station_train_code,
start_time,
arrive_time,
lishi,
} = queryLeftNewDTO;
return {
车次: station_train_code,
始发站: from_station_name,
目的地: to_station_name,
开车时间: start_time,
到达时间: arrive_time,
历时: lishi,
商务座特等座: queryLeftNewDTO["商务座特等座"],
一等座: queryLeftNewDTO["一等座"],
二等座: queryLeftNewDTO["二等座"],
软卧一等卧: queryLeftNewDTO["软卧一等卧"],
硬卧二等卧: queryLeftNewDTO["硬卧二等卧"],
软座: queryLeftNewDTO["软座"],
硬座: queryLeftNewDTO["硬座"],
无座: queryLeftNewDTO["无座"],
};
})
.filter((item) => {
if (!filter.length) return true;
return !!filter.find(
(ff) =>
item["车次"].includes(ff.type) &&
item[ff.site] !== "无座" &&
item[ff.site] !== "--"
);
});
}
使用
function getList({ date, from, to, filter = [] }) {
const station = getStationMap();
get(
`https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=${date}&leftTicketDTO.from_station=${station[from]}&leftTicketDTO.to_station=${station[to]}&purpose_codes=ADULT`
)
.then((res) => {
if (res.httpstatus === 200 && res.data.flag === "1") {
const list = cr(res.data.result, res.data.map, filter);
// 提供接口
console.log(list);
// 把获取到的数据,抛给你的服务
// fetch(`youurl`, { data: list });
} else {
console.log("请求失败1:", res);
}
})
.catch((e) => {
console.log("请求失败2:", e);
});
}
效果
