12306与抢票插件初识

序. 无数巨人的肩膀

12306购票浅显研究

http://xiaowa.org/modules.php?link=read_article&id=129 .

基于HTTPS协议的12306抢票软件设计与实现--相关接口以及数据格式

http://m.blog.csdn.net/blog/MINEZHANGHAO/18769159 .

解析12306订票流程

http://blog.csdn.net/lzqwebsoft/article/details/18674635 .

玩转新版12306之抢票篇 

http://blog.csdn.net/yaerfeng/article/details/18013415 .

根据大牛们对12306网站的分析,我模仿去年的插件开源代码进行重写,以适应现在新版12306网站。

本文为阶段性成果记录,有很多不足,敬请大家提示和赐教。

 

 

0.写js脚本要考虑的

我们脚本中写的变量或者元素可能与页面发生重复,需要保护本地变量不被外部变量污染

(function($j) {
    // your code
})(jQuery)

 

考虑页面如果突然不支持jQuery我们的脚本就不能运行了,需要检测并加载我们的脚本同时,保留原来$的方法

原理知道了,下面这个为高手写成的兼容jQuery框架,我们只需将callback函数作为参数写好就行。

withjQuery(function($, window) {}, true); 在框架内就可以不与外界冲突的使用$

另外,用jQuery加载脚本jQuery.getScript("/js/script.js").done(function() {/* Success CallBack */}).fail(function(){/*Fail CallBack*/});

function withjQuery(callback, safe) {
    if ( typeof (jQuery) == "undefined") {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js";

        if (safe) {
            var cb = document.createElement("script");
            cb.type = "text/javascript";
            cb.textContent = "jQuery.noConflict();(" + callback.toString() + ")(jQuery, window);";
            script.addEventListener('load', function() {
                document.head.appendChild(cb);
            });
        } else {
            var dollar = undefined;
            if ( typeof ($) != "undefined")
                dollar = $;
            script.addEventListener('load', function() {
                jQuery.noConflict();
                $ = dollar;
                callback(jQuery, window);
            });
        }
        document.head.appendChild(script);
    } else {
        setTimeout(function() {
            //Firefox supports
            callback(jQuery, typeof unsafeWindow === "undefined" ? window : unsafeWindow);
        }, 30);
    }
}

 

1.查票页面优化

对查询票的页面进行注入,获得用户更适合抢票的体验。

var ticketType = new Array();
        $("#float th").each(function(i, e) {
            ticketType.push(false);
            if (i > 3 && i < 15) {
                ticketType[i] = true;
                var that = $("<input/>").attr("type", "checkBox").attr("checked", true);
                that.index = i;
                that.change(function() {// 绑定change事件
                    ticketType[that.index] = this.checked;
                });
                $(e).append(that);
            }
        });
function notify(str, timeout, skipAlert) {// Webkit 桌面通知
            if (window.webkitNotifications && window.webkitNotifications.checkPermission() == 0) {
                var notification = webkitNotifications.createNotification("http://www.12306.cn/mormhweb/images/favicon.ico", '抢票消息', str);
                notification.show();
                if (timeout) {
                    setTimeout(function() {
                        notification.cancel();
                    }, timeout)
                }
            } else {
                if (window.webkitNotifications && window.webkitNotifications.checkPermission() != 0) {
                    window.webkitNotifications.requestPermission();
                }
                if (!skipAlert) {
                    alert(str);
                }
            }
        }
function checkTickets(row) {
            var v1 = $special.val();
            if (v1 != '') {
                var v2 = $.trim($(row).find(".train a").text());
                if (v1.indexOf(v2) == -1)
                    return false;
                if ($(row).find(".no-br a").length == 0) {
                    return false;
                }
            }
            var cnt = 0;
            $(row).find("td").each(function(i, e) {
                if (i > 0 && i < 12 && ticketType[i + 3]) {
                    var info = $.trim($(e).text());
                    if (info != "--" && info != "无") {
                        $(this).css("background-color", "#2CC03E");
                        cnt++;
                    }
                }
            });
            if (cnt && Block) {
                $(row).find(".no-br a").click();
                $.post("https://kyfw.12306.cn/otn/confirmPassenger/initDc", {
                    "_json_att" : ""
                }, function(data) {
                    console.log(data);
                    var str = $.trim(data.match(/globalRepeatSubmitToken.+/));
                    str = str.substr(str.indexOf("= ")).match(/[a-zA-Z0-9]+/);
                    if (str != "")
                        SubmitToken = str;
                });
                setTimeout(function() {
                    var $t = $("#defaultwarningAlert_id");
                    if ($t.length) {
                        $t.remove();
                        return false;
                    }
                    $t = $(".dhtmlx_wins_body_outer");
                    if ($t.length) {
                        setTimeout(function() {
                            $t = $t.find('#loginForm');
                            $t.find("input").eq(0).val('401334029@qq.com');
                            $t.find("input").eq(1).val('sks_168168');
                            $('#randCode').keyup(function(e) {
                                var str = $.trim(e.target.value);
                                if (str.length == 4)
                                    $t.find("#loginSubAsyn").get(0).click();
                            });
                        }, 1000);
                    }
                }, 100);
            }
            return cnt;
        }

 

2.用户登录优化

从这里开始就涉及复杂的信息跟踪,我这里仅实现简单的POST登录跳转功能。

这里还需要用户来输入验证码,这里补充一下JS产生验证码的一种方法: Math.random().toString(16).substr(4,4); 随机一个小数转成16进制后取4到8地址的字符。

function submitForm() {
            $.ajax({
                type : "POST",
                url : "https://kyfw.12306.cn/otn/login/loginAysnSuggest",
                data : {
                    "loginUserDTO.user_name" : $("#username").val(),
                    "userDTO.password" : $("#password").val(),
                    "randCode" : $("#randCode").val()
                },
                beforeSend : function(xhr) {
                    try {
                        xhr.setRequestHeader('X-Requested-With', {
                            toString : function() {
                                return '';
                            }
                        });
                        xhr.setRequestHeader('Cache-Control', 'max-age=0');
                        xhr.setRequestHeader('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8');
                    } catch(e) {
                    };
                },
                timeout : 30000,
                success : function(msg) {
                    // for( var key in msg)
                    // alert(msg[key]);
                    if (msg['data'].loginCheck != 'Y') {
                        alert('请输入正确登录信息');
                        reLogin();
                    } else {
                        alert('登录成功,开始查询车票吧!');
                        window.location.replace(queryurl);
                    }
                },
                error : function(msg) {
                    reLogin();
                }
            });
        }

 

3.针对订票过程优化

给url添加一个timeStamp来避免浏览器缓存得不到正确数据。

setTimeout(function() {
            if (!$("input.check:checked").length) {
                $("input.check:first").click();
            }
            $.post("https://kyfw.12306.cn/otn/confirmPassenger/initDc", {
                "_json_att" : ""
            }, function(data) {
                var str = $.trim(data.match(/globalRepeatSubmitToken.+/));
                str = str.substr(str.indexOf("= ")).match(/[a-zA-Z0-9]+/);
                if (str != "")
                    SubmitToken = str;
            });
            $("#randCode").off('keyup');
            $("#randCode").focus().keyup(function(e) {
                var str = $.trim(e.target.value);
                if (str.length == 4) {
                    $.post("https://kyfw.12306.cn/otn/passcodeNew/checkRandCodeAnsyn", {
                        "randCode" : $("#randCode").val(),
                        "rand" : "randp"
                    }, function(data) {
                        if (data.data == "N") {
                            $(".i-re").click();
                        } else {
                            submitForm();
                            return;
                        }
                    });
                }
            });

            var userInfoUrl = "https://kyfw.12306.cn/otn/queryOrder/initNoComplete";

            var count = 1, freq = 1000, doing = false, timer, $msg = $("<div style='padding-left:470px;'></div>");

            function submitForm() {
                timer = null;
                var info;

                $.post("https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs", {
                    "REPEAT_SUBMIT_TOKEN" : SubmitToken,
                    "_json_att" : ""
                }, function(data) {

                    info = eval(data.data.normal_passengers)[0];

                    $.ajax({
                        url : "https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo",
                        data : {
                            'cancel_flag' : '2',
                            'bed_level_order_num' : '000000000000000000000000000000',
                            'REPEAT_SUBMIT_TOKEN' : SubmitToken,
                            "randCode" : $("#randCode").val(),
                            'passengerTicketStr' : '3,0,' + '1,' + info.passenger_name + ',1,' + info.passenger_id_no + ',' + info.mobile_no + ',N',
                            'oldPassengerStr' : info.passenger_name + ',1,' + info.passenger_id_no + ',' + info.mobile_no + info.passenger_type + '_',
                            'tour_flag' : 'dc'
                        },
                        beforeSend : function(xhr) {
                            try {
                                xhr.setRequestHeader('X-Requested-With', {
                                    toString : function() {
                                        return '';
                                    }
                                });
                                xhr.setRequestHeader('Cache-Control', 'max-age=0');
                                xhr.setRequestHeader('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8');
                            } catch(e) {
                            };
                        },
                        type : "POST",
                        timeout : 30000,
                        success : function(data) {
                            if (data.data.submitStatus) {
                                $.post("https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue", {
                                    'REPEAT_SUBMIT_TOKEN' : SubmitToken,
                                    //"leftTicketStr" : "1015653007404405002630279503121015650165",
                                    'purpose_codes' : '00',
                                    'passengerTicketStr' : '3,0,' + '1,' + info.passenger_name + ',1,' + info.passenger_id_no + ',' + info.mobile_no + ',N',
                                    'oldPassengerStr' : info.passenger_name + ',1,' + info.passenger_id_no + ',' + info.mobile_no + info.passenger_type + '_',
                                }, function(msg) {
                                    alert(msg.data.submitStatus);
                                    if (msg.data.submitStatus) {
                                        var audio;
                                        if (window.Audio) {
                                            audio = new Audio("http://www.w3school.com.cn/i/song.ogg");
                                            audio.loop = true;
                                            audio.play();
                                        }
                                        setTimeout(function() {
                                            if (confirm("车票预订成,去付款?")) {
                                                window.location.replace(userInfoUrl);
                                            } else {
                                                if (audio && !audio.paused)
                                                    audio.pause();
                                            }
                                        }, 100);
                                    } else {
                                        stop(msg.data.errMsg || '未知错误');
                                    }
                                })
                            } else {
                                var reTryMessage = ['用户过多', '验证码', '请不要重复提交', '没有足够的票!', '车次不开行'];
                                for (var i = 0; i < reTryMessage.length; i++) {
                                    if (data.data.errMsg.indexOf(reTryMessage[i]) != -1) {
                                        reSubmitForm(reTryMessage[i]);
                                        return;
                                    }
                                };
                                stop(data.data.errMsg || '未知错误');
                            }
                        },
                        error : function(msg) {
                            reSubmitForm("网络错误");
                        }
                    });
                })
            };
            function reSubmitForm(msg) {
                if (!doing)
                    return;
                count++;
                $msg.html("(" + count + ")次自动提交中... " + (msg || ""));
                timer = setTimeout(submitForm, freq || 50);
            }

            function stop(msg) {
                doing = false;
                $msg.html("(" + count + ")次 已停止");
                $('#refreshButton').html("自动提交订单");
                timer && clearTimeout(timer);
                if (msg != '')
                    alert(msg);
            }

            if ($("#refreshButton").size() < 1) {

                $(".lay-btn").append($("<a style='padding: 5px 10px; background: #2CC03E;border-color: #259A33;border-right-color: #2CC03E;border-bottom-color:#2CC03E;color: white;border-radius: 5px;text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.2);'></a>").attr("id", "refreshButton").html("自动提交订单").click(function() {
                    //alert('开始自动提交订单,请点确定后耐心等待!');
                    if (this.innerHTML.indexOf("自动提交订单") == -1) {
                        doing = false;
                        stop();
                    } else {
                        doing = true;
                        this.innerHTML = "停止自动提交";
                        reSubmitForm();
                    }
                    return false;
                }));
                $(".lay-btn").append("自动提交频率:").append($("<select id='freq'><option value='50' >频繁</option><option value='500' selected='' >正常</option><option value='2000' >缓慢</option></select>").change(function() {
                    freq = parseInt($(this).val());
                })).append($msg);
            }
        }, 500);

 

posted @ 2014-02-06 01:16  匡时@下一站.info  阅读(2223)  评论(0编辑  收藏  举报