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;
}

结果如下:


image.png

2.请求接口,获取混淆的余票信息

参数说明:

代码如下:

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);
        });
}

效果


image.png

三、代码地址
https://github.com/ThreesomeWiki/watch-12306

上一篇 下一篇

猜你喜欢

热点阅读