站在巨人的肩膀上,我所寫的東西,也會開源分享出來!已經能正常用了,但是還需優化一些小bug。
授人以魚不如授人以漁,我把思路分享出來。
如果程序優化好了,我會將源碼放在這里今日校園實現自動檢測並提交最新表單
也可以直接訪問我博客
一、抓包(重點)
1.1 如何抓包
Fiddler4電腦端與手機端抓包的教程,我不多bb了。點這個鏈接里面有具體步驟,這個大佬是專門學習機器學習的,他的博客放到這里。
一開始,我是用的Fiddler4來進行抓包的,但是涉及到ssl-pinning的問題。導致抓包失敗,也就是抓取過程中,一堆灰色鏈接。同時,手機上的網路也會被斷開。
之后,我就開始考慮,要不用手機抓包,就下載了HttpCannary,HttpCanary有普通版和高級版之分,建議下載高級版,同樣會遇到ssl-pinning的問題,具體解決方法請移步到系統證書的安裝,解決APP抓不到包,下載軟件點這里
1.2 我的解決方法
此節是廢話,請略過。
我一開始用LuckyPatcher,很幸運的是,雖然顯示破解授權失敗,但打開的時候,發現能用了。
下一步,就是安裝系統證書了,我就把手機root了,我的手機是小米的,直接root就行。
但是,還是在安裝系統證書的過程中出了問題,不能往系統里面移動證書,原因是沒有權限。
后來百度了一下,發現,MIUI的root權限,從Android7之后,就沒有完整的root權限了。除非刷第三方系統。
但是我又舍不得自己的MIUI12。
接下來,就准備用模擬器了,我下載的是逍遙安卓模擬器。安卓的是4.4版本系統,刷入了xposed框架,安裝了justtrustme模塊。
然后,打開Fiddler抓包,Yes!
有了Cpdaily-Extension跟MOD_AUTH_CAS這兩條數據,就能模擬提交了。
抓包問題就此解決。耗費了我一整天的時間
二、Java模擬get跟post請求
這個算是套模板吧,都是這個套路,直接上代碼。不要拿來就用,還是根據實際情況進行修改的。
/**
* HttpUtil類
* @author kit chen
* @description 用來模擬發送post請求
*/
public class HttpUtil {
public static String sendPost(String url, String param,Map<String,String> headers) {
BufferedWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
Set<Entry<String, String>> set=headers.entrySet();
for(Entry<String,String> header:set) {
conn.setRequestProperty(header.getKey(), header.getValue());
}
conn.setDoOutput(true);
conn.setDoInput(true);
out = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8"));
out.write(param);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("發送 POST 請求出現異常!" + e);
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
}
三、模擬請求中的問題
通過抓包獲取了請求頭跟請求參數,請求參數還好說。
在抓取請求頭的時候,遇到了點問題。
通過測試發現,如果想要成功提交內容,需要Cpdaily-Extension跟MOD_AUTH_CAS。
如果設備不去主動退出的話,Cpdaily-Extension是會一直存在有效的。類似的像QQ也是這樣的。我在抓取Cpdaily-Extension的過程中,嘗試訪問各種頁面,但是都沒法獲取到這個的值。哪怕是在登錄的時候,也沒有這個參數。只有在提交的時候,才能抓取到。
像MOD_AUTH_CAS這個的值,類似於session,是有有效期的。我目前還沒有測試一直讓這個東西保持有效。這個值,大概6個小時左右,就會失效了,需要重新登錄網頁獲取。
問了大佬,好像是涉及到了cas單點登錄的知識,這塊我也不懂。學!
四、監測表單並返回表單號
今日校園有個獲取今日最新表單的接口,如果沒有的話,里面某個數據會是個空數組。
接口/wec-counselor-collector-apps/stu/collector/queryCollectorProcessingList
post的請求參數{"pageSize": 6,"pageNumber": 1}
這個pageSize是指返回幾條數據,響應請求中,我記得返回的json字符串,最多就只有6個參數,所以這個傳個6就行了。大於等於6
返回的內容
{
"code": "0",
"message": "SUCCESS",
"datas": {
"totalSize": 0,
"pageSize": 6,
"pageNumber": 1,
"rows": [
"wid":"xx",
"formWid":"xx",
"isHandled":"0"
...
]
}
}
我們要的就是這個wid、formWid跟isHandled。isHandled表示是否提交,非0為提交。
監測到有rows有數據,並且isHandled未提交的時候,我們就可以進行模擬提交了。
五、獲取學校表單號
這個還有一個坑就是,每天的學校的表單號schoolTaskWid不是固定的,由此,我們就需要來模擬請求來獲取schoolTaskWid
接口/wec-counselor-collector-apps/stu/collector/detailCollector
post請求參數 {"collectorWid": 傳進來第三步獲取的collectWid}
注意:
這sb接口開發者,一開始定義的是collectWid,結果后面又成了collectorWid,一開始在這邊把我給坑了,需要注意。
這個接口獲取的是collectorWid,第三步獲取的是collectWid,其實他倆是一個東西。
大致的返回內容
{
"code": "0",
"message": "SUCCESS",
"datas": {
"collector": {
"wid": "8888",
"formWid": "164",
"priority": "5",
"endTime": "8888-88-88 88:00:00",
"currentTime": "8888-88-88 88:00:00",
"schoolTaskWid": "8888",
"isConfirmed": 1,
"senderUserName": "牛逼學院(牛逼老師)",
"createTime": "8888-88-88 88:00:00",
"attachmentUrls": null,
"attachmentNames": null,
"attachmentSizes": null,
"isUserSubmit": 1,
"fetchStuLocation": true,
"address": "xx省xx市xx縣"
//這個根據地圖上面的為准,大致就是省市縣
},
"form": {
"wid": "164",
"formTitle": "8月8日學生身體健康狀況調查",
"formContent": "https://wecres.cpdaily.com/counselor/1076158768111098/content/d1c0daf5604af56fbccfadaf28cdbd82.html",
"backReason": null,
"isBack": 0,
"attachments": []
}
}
}
這里我們需要獲取schoolTaskWid。
六、獲取詳細表單
今日校園還有一條驗證就是每次請求的表的id,以及表選項的id都是變化的。
所有,我們還需要抓取表的詳細表單。
接口/wec-counselor-collector-apps/stu/collector/getFormFields
參數{"pageSize":30,"pageNumber":1,"formWid":formWid,"collectorWid":collectorWid}
返回的內容,依你們老師的設定為准,不放結果了。
七、模擬Post請求提交
7.1 思路
通過上面,我們獲取到了formWid,collectWid,schoolTaskWid,address,form。
接下來,我們構造出post的json字符串請求體。
發送!
成功!
7.2 擴展-郵件通知
如果提交成功,或者提交失敗。都會發通知郵件給我。
但是,試了幾次,經常報錯554 DT:SPM
,也就是被當做垃圾郵件駁回了。
嘗試了好幾個郵箱,像139,163,qq郵箱,都會有這個問題,網上說設置端口啊,不要25,要465...開啟ssl...等等
如果涉及到敏感詞,什么簽到、自動,仍然沒有一個奏效的,都沒當成垃圾郵件處理。
剛好看到一個大佬寫的博客,建議用騰訊企業郵箱,試了一下,果然ok了。
記錄一次Could not connect to SMTP host: smtp.163.com, port: 25的解決辦法
騰訊雲或者阿里雲,是默認禁用25端口的
我附上發郵件的代碼
public class SendMail {
public static String send(String[] mail) {
Properties properties = new Properties();
properties.put("mail.transport.protocol", "smtp");// 連接協議
properties.put("mail.smtp.host", "smtp.exmail.qq.com");// 主機名
properties.put("mail.smtp.port", "587");// 端口號
properties.put("mail.smtp.auth", "true");//設置smtp是否需要認證
properties.put("mail.smtp.ssl.enable", "true");// 設置是否使用ssl安全連接 ---一般都使用
properties.put("mail.debug", "false");// 設置是否顯示debug信息 true 會在控制台顯示相關信息
try{
Session session = Session.getInstance(properties);
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("xxxxxxxxx@xxxxx.onexmail.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("meethigher@qq.com"));
message.setSubject(mail[0]);
message.setText(mail[1]);
message.setSentDate(new Date());
Transport transport = session.getTransport();
transport.connect("xxxxxxxxx@xxxxxx.onexmail.com", "xxxxxx");//登錄發信賬號
transport.sendMessage(message, message.getAllRecipients());
transport.close();
return "郵件發送成功";
}catch (Exception e){
return "郵件發送失敗";
}
}
}
7.3 運行結果
去我博客看吧
八、總結
8.1 感謝大佬
記錄一次Could not connect to SMTP host: smtp.163.com, port: 25的解決辦法
還是那句話,站在巨人的肩膀上
8.2 個人收獲
連着兩天,早上5點就起。
因為這個是學校的老師發的表單,我沒有老師權限,沒法模擬。
所以,只能,每天早起,在表單未提交之前,進行測試。這也是最難受的一點。
今天專業課考試,我當時寫代碼寫得正在興頭上,結果作業沒給交上去。估計這學期也就考個60分吧。無所謂了,反正我也不是學霸,計較個錘子。而且,我這學期,也都沒咋聽課,天天在家里就知道玩。每次都下定決心好好學習,結果,嘿嘿...
總得來說,抓包還是很關鍵的。
這個博客算是整理整個的思路,如果思路看明白了,那么,實現這樣的功能就不難了。
我看網上也有不少的類似程序,但是大多數是Python開發的,確實,Python在處理數據的時候,很舒服,給我的感覺,就是跟JavaScript一樣,就是舒服。PHP如果實現這個功能的話,也會比較輕松。
由於我現在正在學java,還沒學透,正好可以拿這個練練手。畢竟,java就像是我的初戀,雖然她身材很臃腫,但我依然愛她啊!
處理過程中,真的感覺人生苦短,多用python。
像這樣的功能,好多編程語言都能實現,Java不是不能,只是太繁瑣了。
如果我再次寫這個的話,首選Python,其次Nodejs。
在分層方面,還是覺得自己做地不太好,像學過的繼承多態,我在處理的過程中,就是一直在硬寫、悶頭寫。自己的代碼也能看得出毛病來,但是想優化,卻又不知從何改起。一方面,是對學過的東西,沒有徹底理解;另一方面,也是自己的項目經驗太少了。
一定要花時間,彌補這方面的不足!