2020.05.31更新:发现自己以前好菜啊……(

慢慢来吧……


摘要:

想利用爬虫实现半夜自动抢图书馆座位的功能,这样晚上就可以多睡一会了……

但是提交申请时发现有一个参数很诡异……

下面就是研究这个参数的生成方式,过程很奇葩 主要还是因为我是新手

研究过程曲折但是很有趣,因此记录一下

如果你是大佬或者懒得往下慢慢看,那我直接告诉你结论好了——就是网站自己的js代码没有生成这个参数,这个参数只能是jQuery本身在提交GET请求时额外添加的,后来发现这参数其实就是时间戳……


登陆已经解决,是一个POST,抓对包之后几乎没什么门槛

提交预约申请使用了Ajax异步技术,因此只需要模拟js脚本提交GET请求即可

抓包分析看到"act":"set_resv"&act=set_resv

在源码VM310中搜索set_resv,看到第537行有对于fRsv()的调用

pro.j.rsv.fRsv("set_resv", $("form:first", dlg), function () {
                if (uni_calendar_dft_opt.submitSuc) {
                    uni_calendar_dft_opt.submitSuc(dlg, obj);
                }
                else {
                    var msg = '申请提交成功,是否跳转查看预约信息?';
                    if (parseInt(obj.minUser) > 1) {
                        msg += "<br/><br/><div style='font-weight:bold;'>" + uni.translate("注意!生效后需至少") + "<span style='color:red;font-size:bold;'>" + obj.minUser + "</span>" + uni.translate("人刷卡,否则将记为违约!") + "</div>";
                    }
                    uni.confirm(msg, function () {
                        $("#user_center").trigger("click");
                    }, function () {
                        uni.reload();
                    });
                    $(".group_id", dlg).val("");
                    $(".group_name", dlg).html("小组未创建");
                    dlg.dialog("close");
                }
                //btn.removeAttr("disabled");
            }, function (rlt) {
                
                uni.msgBox(pro.translate(rlt.msg));
                //btn.removeAttr("disabled");
            }, function () {
                uni.msgBox(uni.translate("异步连接出现异常!"));
                //btn.removeAttr("disabled");
            });

其中传入的实参有一个就是我们的”set_resv”,另外还有一个实参是一个回调函数,用于申请成功后更新页面信息(弹窗),这就是Ajax提交申请的流程。

因此猜测fRsv()完成了对于url的生成和提交

pro.js中1056行找到了fRsv()的原型

fRsv: function (act, $f, suc, fail, err) {
            pro.j.fGetS(this.p, act, $f, suc, fail, err);
        },

它又调用了fGetS: (:179)

//get方式 form提交 拓展方法
fGetS: function (url, act, $f, suc, fail, err) {
            var data = {};
            data.act = act;
            data.$f = $f;
            uni.j.fGet(url, data, function (rlt) {
                pro.ckV(rlt, suc, fail);
            }, err);
        },

注意urlthis.p对应,因此分析p很关键,因为我们很关心url中的一个诡异的参数_,一旦知道了这个参数就🆗了

类内的p出现在792行

pro.j.rsv = {
        //路径
        p: pro.dir + "ajax/reserve.aspx",
    ...

果然见到了我们想要的ajax/reserve.aspx

但是线索有断了,因为p在之后就没有变化过了……

因此p内没有这个参数……

再次将焦点转向fRsv(),看看它如何被调用的

pro.j.rsv.fRsv("set_resv", $("form:first", dlg), function () {/* 成功之后的提示*/},function (rlt) {uni.msgBox(pro.translate(rlt.msg));}, function () {uni.msgBox(uni.translate("异步连接出现异常!"));});

与原型对比分析

act“set_resv”
$f$(“form:first”, dlg)
sucfunction () {/* 成功之后的提示*/}
failfunction (rlt) {uni.msgBox(pro.translate(rlt.msg));}
errfunction () {uni.msgBox(uni.translate(“异步连接出现异常!”));}

猜测$f是关键

$("form:first", dlg)是jQuery的多项选择器,匹配出来应该是在dlg中的第一个form

再看看调用

// pro.j.fGetS(this.p, act, $f, suc, fail, err);
fGets("http://******/ClientWeb/ajax/reserve.aspx", "set_resv", $f, suc, fail, err)
// http://******/ClientWeb/pro/ajax/reserve.aspx?dialogid=&dev_id=685&lab_id=&kind_id=&room_id=&type=dev&prop=&test_id=&term=&number=&test_name=&start=2019-03-30+18%3A00&end=2019-03-30+20%3A00&start_time=1800&end_time=2000&up_file=&memo=&act=set_resv&_=1553927422652

$f应该对应的就是我们的申请表,也就是抓到的GET请求中的绝大多数参数的来源

果然在页面中找到了它

完全吻合

看来WebForm就是这个Form+act(“set_resv”)+那个诡异的参数_……

然鹅_还是不知道如何生成的……

因此又猜测生成这个参数的位置就在于fGets()

fGetS: function (url, act, $f, suc, fail, err) {
            var data = {};
            data.act = act;
            data.$f = $f;
            uni.j.fGet(url, data, function (rlt) {
                pro.ckV(rlt, suc, fail);
            }, err);
        },

果然它将act的参数以及form中的参数合并成了data,并传给fGet()

其中调用到的ckV()位于pro.js的114行

//检查返回值
ckV: function (rlt, suc, fail) {
            if (rlt == undefined) {
                uni.msgBox("返回了空值!", null, null, "error");
                return false;
            }
            else {
                if (rlt.ret == 0) {
                    if (fail == undefined) { uni.msgBox(rlt.msg, null, null, "warning"); uni.log.set("msg", rlt.msg + "/" + rlt.act); }
                    else fail(rlt);
                }
                else if (rlt.ret > 0) {
                    if (suc == undefined) { uni.msgBox(rlt.msg, null, null, "success"); uni.log.set("msg", rlt.msg + "/" + rlt.act); }
                    else suc(rlt);
                }
                else if (rlt.ret == -1) {//登录超时
                    uni.msgBox(rlt.msg, "", function () { location.reload(); }, "warning");
                    uni.log.set("msg", rlt.msg + "/" + rlt.act);
                }
                return true;
            }
        }

估摸着这个函数主要是用于处理服务器返回信息用的,先搁在一边……

回到网页源码,找到了uni的出处uni.lib

//-------------------------------------------------------------------jquery第三方 插件-----------------------------------
//异步上传

第三方插件可还行……

果然找到fGet()

//get方式 form提交(data.act 操作命令 data.$f 表单Jquery对象)
    fGet: function (url, data, suc, err) {
        var e = err || this._ajaxErr;
        this._get(url, data, suc, e, 2);
    },

进一步找到_get()

//基础ajax方法 get方式 flag=1 js对象转url参数 flag=2 form提交 flag=3 uri编码
    _get: function (url, data, suc, err, flag, type) {
        var d = data;
        if (flag === 1) {
            d = uni.obj2Url(data);
        }
        else if (flag === 2) {
            d = $(data.$f).serialize() + "&act=" + data.act;
        }
        else if (flag === 3) {
            d = encodeURI(data);
        }
        if (d != null && d != "") {
            if (d.length > 2000) {//当参数超出url长度限制,转post方式
                this.post(url, uni.url2Obj(d), suc, err);
                return;
            }
            else {
                url = url + "?" + d;
            }
        }
        var len = this.history.length;
        if (len > 0) {
            var last = this.history[len - 1];
            if (last.act == url && last.ajax_state == "sending") {
                return;//重复提交 丢弃
            }
        }
        var sta = { ajax_state: "sending", act: url };
        this.history.push(sta);
        $.ajax({
            type: "GET",
            cache: false,
            timeout: 150000,
            buf: data,
            url: url,
            dataType: type || "json",
            success: suc,
            error: err,
            beforeSend: function () {
                uni.j.swit++;
                uni.showWait();
            },
            complete: function () {
                uni.j.swit--;
                if (uni.j.swit == 0) uni.hideWait();
                sta.ajax_state = "complete";
            }
        });
    },

看了一遍,貌似url并没有发生改变,说明_不是这一步加上去的……

哭了老哥加油

回归本质,把网页html源码下载下来本地分析……

还是没有找到_……

回到chrome进行调试

意外发现第三方插件确实没有生成_,上面的f中的网址最后没有该参数!

emmm,看来只能是jQuery搞的鬼,可是这代码被混淆了……


突然发现

typora也有这个标记……

原来是时间戳……

破案了!


果然还是缺乏经验,不过这一通操作算是积累了不少阅读js源码的经验……