原因
由於公司訂餐系統選用的問卷星系統,有時候工作忙忘記訂餐導致沒飯喫,終於下定決心研究一下怎麼能更方便的喫飯,於是開始研究怎麼用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。