原因
由于公司订餐系统选用的问卷星系统,有时候工作忙忘记订餐导致没饭吃,终于下定决心研究一下怎么能更方便的吃饭,于是开始研究怎么用curl来自动化处理问卷星答卷。
实现
首先我们需要了解问卷星页面。
打开一个问卷星页面。
这里是我的一个测试页面。(https://www.wjx.cn/jq/80375841.aspx)
尝试提交。
发现当点击提交的时候会向此地址发送数据。
发送的数据格式如下:
submittype: 1
curID: 80375841
t: 1591198942624
starttime: 2020/6/3 23:42:14
ktimes: 38
rn: 1878089202
hlv: 1
jqnonce: e38ac63f-83c4-433c-8b61-3e1c41b467ae
jqsign: m;0ik>;n%0;k<%<;;k%0j>9%;m9k<9j<>?im
form中包含用户输入的答案
submitdata: 1$3}2$test
这里form比较好理解,表示的第一个空选择的是第三个选项,第二个空填写的是test
主要是param携带的东西。
根据多次的实验。
submittype,hlv是不变的
curID表示当前的页面ID,就是问卷星后面跟的数字。
那么接下来要解开其余ID的迷。
t: 1591198942624 //表示当前时间戳 毫秒 这里表示的是提交时间!!
starttime: 2020/6/3 23:42:14 //当前打开页面时间
ktimes: 38 //答题时间,猜测
rn: 1878089202 //目前暂且不知
jqnonce: e38ac63f-83c4-433c-8b61-3e1c41b467ae //不知
jqsign: m;0ik>;n%0;k<%<;;k%0j>9%;m9k<9j<>?im //不知,但是是一个签名认证
这时候迷惑的主要是几个很奇怪的ID。
rn,jqnonce,jqsign,ktimes的获取。只要搞到这几个ID怎么来的就可以了。
我们抓一下答题页面。
此时,就剩rn和ktimes,jqsign不知道怎么来的。
我们看到其中有一个rndnum和rn一样,那么基本可以确定。rn,jqnonce,starttime都可以获取页面中原有的。
那么jqsign到底怎么来的呢。
我们看一下页面点击事件触发的js。
看代码,在代码中搜索jqsign
window.jqnonce &&
(e += "&jqnonce=" + encodeURIComponent(window.jqnonce),
k = dataenc(window.jqnonce),
e += "&jqsign=" + encodeURIComponent(k)),
jqsign是调用了dataenc方法根据jqnonce计算出来的。
function dataenc(a) {
var c, d, e, b = ktimes % 10;
for (0 == b && (b = 1), c = [], d = 0; d < a.length; d++) e = a.charCodeAt(d) ^ b,
c.push(String.fromCharCode(e));
return c.join("")
}
这段代码获取jsqnonce的每一个字符的Unicode码和b做抑或,最后再把相应的Unicode码转换为对应的字符。
我用PHP重写了,代码在下面。
那么到了这一步,我们把参数中需要获取的已经获取完全了。
ktimes也只是取了一个累加的数值,我们给随机即可。
那么此时,我们就把需要的数据全部拿到了,下面贴一下用PHP实现的代码。
//dataenc实现
function dataenc($a,$ktime)
{
$c = "";
for ($d = 0;$d < strlen($a);$d++){
$b = $ktime % 10;
if ($b == 0) $b = 1;
//转换unicode
$e = ord($a[$d]) ^ $b;
//unicode转为字符
$c = $c . utf8_encode(chr($e));
}
return $c;
}
//获取毫秒
function getMillisecond() {
list($t1, $t2) = explode(' ', microtime());
return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
}
//获取问卷星提交url
function getWJXSubmitURL($wjxId)
{
$microTime = getMillisecond() + mt_rand(100,300);
$bookHtml = "https://www.wjx.cn/jq/".$wjxId.".aspx";
$s = request_by_curl($bookHtml, "",$bookHtml);
//从页面中获取starttime,jqnonce,rndnum这三个值
preg_match_all('/starttime=\"(.*)\"/',$s,$startTimes);
preg_match_all('/jqnonce=\"(.*)\"/',$s,$jqnonces);
preg_match_all('/rndnum=\"(.*)\"/',$s,$rndnum);
$startTime = urlencode($startTimes[1][0]);
$jqnonce = $jqnonces[1][0];
$rn = $rndnum[1][0];
//ktimes随机即可
$ktimes = mt_rand(10,50);
$jqsign = urlencode(dataenc($jqnonce,$ktimes));
$param = "submittype=5&curID=".$wjxId."&t=".$microTime."&starttime=".$startTime.
"&ktimes=".$ktimes."&rn=".$rn."&hlv=1&jqnonce=".$jqnonce."&jqsign=".$jqsign."&jpm=21";
$dinnerURL = "https://www.wjx.cn/joinnew/processjq.ashx?".$param;
return $dinnerURL;
}
结果
尝试用此脚本每隔50ms运行一次,总共运行100次,后台全部接收到响应,数据也正确存入,但是之后再提交就需要验证了。
如果有需要刷脚本请代理ip。