模拟教务评教(强智教务)—一件评教实现原理
前言
- 前不久,學(xué)校有個(gè)校園幫助型app某某圈因?yàn)橐患u(píng)教功能被教務(wù)批評(píng)了。現(xiàn)在有很多查成績,查課程的app,他們的實(shí)現(xiàn)原理到底是啥了。這兩天來到發(fā)小揚(yáng)州這邊,學(xué)習(xí)實(shí)現(xiàn)了這個(gè)功能,并且用java和python都寫了一下,但是鑒于web端只會(huì)java,最后集成到springboot部署到服務(wù)器提供的小服務(wù)。
- 以前只知道這些東西是爬蟲爬出來的,原本以為非常簡單,自己研究了一下發(fā)現(xiàn)還是有很多的坑和坎。大致有一下幾點(diǎn):
- 模擬登陸,登陸是所有校園app要解決的第一難題,如果沒驗(yàn)證碼還好,但是如果有驗(yàn)證碼解決思路有兩個(gè),抓包找圖片手動(dòng)打碼,如果會(huì)點(diǎn)圖像識(shí)別可以自己調(diào)算法,恰巧咱們科大有個(gè)不需要驗(yàn)證碼的入口,在官網(wǎng)可以找到。
- 提交表單問題。在我的測試過程中遇到兩點(diǎn)錯(cuò)誤,第一就是正確提交表單后發(fā)現(xiàn)只提交一個(gè)按鈕,這個(gè)原因是因?yàn)樗卸鄠€(gè)key-value是相同參數(shù),也就是他有提交key-set內(nèi)容。還有一個(gè)是提交可以完整提交但是只是保存沒有真正提交,原因是他的js更改參數(shù)內(nèi)容,需要修改,下面會(huì)介紹到。
- 異常處理,提交過的和沒提交的表單內(nèi)容有所不一致,需要進(jìn)行異常處理保證程序可執(zhí)行性,
- 當(dāng)然寫完了還發(fā)現(xiàn)一個(gè)問題就是速度有點(diǎn)慢的問題,我才發(fā)現(xiàn)沒用多線程執(zhí)行,算了算了,反正自己玩玩,就不加了。
步驟
用到的包:
java:jsoup
python:request,re,Beautifulsoup
-
下面開始介紹攻克的整個(gè)步驟(因?yàn)橘~號(hào)被測試用完無法給出更多fidder抓包圖)
-
模擬登陸:
-
這部分算是簡單的了,因?yàn)橐郧爸皇窃囘^一些簡單的模擬登陸。但是對(duì)一些session和cookie理解不夠深刻。導(dǎo)致在這個(gè)地方 當(dāng)時(shí)卡了很久。我原本以為是先請求登陸頁面->帶著這個(gè)頁面的cookie和頁面參數(shù)進(jìn)行登陸->用返回界面的cookie進(jìn)行操作。這個(gè)流程,實(shí)際上他第三部不會(huì)返回cookie,我當(dāng)時(shí)以為那個(gè)地方出問題了 ,用fidder一直找不到問題。其實(shí)他將所有信息都存在session中,不過你執(zhí)行的登陸的操作你的cookie的sessionid這個(gè)參數(shù)在服務(wù)器就是你的身份。
-
所以,你只需要模擬登陸拿著初始界面的cookie就可以完成所有操作了。根據(jù)圖片和網(wǎng)頁的form結(jié)構(gòu)你可以發(fā)現(xiàn)只有兩個(gè)參數(shù)。沒有加密或者隱藏參數(shù),直接懟就可以模擬登陸成功。
-
接著就要根據(jù)初始界面找到評(píng)教的鏈接,有實(shí)驗(yàn)課評(píng)教和理論課評(píng)教。然后就是找到各個(gè)老師的評(píng)教地址,這里他的地址有些不規(guī)則,要用正則或者切割獲得,爬蟲細(xì)節(jié)不做過多介紹
-
最后就是進(jìn)入評(píng)教的表單
我這個(gè)是已經(jīng)評(píng)教過的,沒評(píng)教過的你會(huì)發(fā)現(xiàn)他有很多隱藏元素,還有就是一個(gè)button多個(gè)選項(xiàng)你要選一個(gè),并且不能重復(fù)一樣。就這樣我遍歷元素提交時(shí)候發(fā)現(xiàn)幾個(gè)按鈕只有最后一個(gè)提交成功,老師評(píng)價(jià)也成功,經(jīng)過fidder抓參數(shù)和我控制臺(tái)打印的參數(shù)幾十個(gè)一一對(duì)比,發(fā)現(xiàn)他不是所有都是key-value,有的是key-set(圖中畫框的部分),在處理上java需要多加幾組data的map,而python自帶的字典支持各種形式可以直接用。 -
就這樣,發(fā)現(xiàn)所有提交都有效,但是,只是達(dá)到保存效果,沒有提交。通過抓包再次查看參數(shù)。查看原文代碼會(huì)發(fā)現(xiàn)問題所在—js修改參數(shù)
-
這樣你就發(fā)現(xiàn)問題所在,更改這個(gè)參數(shù)就可以提交成功。但是,會(huì)發(fā)現(xiàn)速度不快啊。。。原來忘記把線程池弄進(jìn)來了。。哎,,算了,不想改代碼了,清冷呵呵的。。附上Java和python版本代碼:
java(已更新加入線程)
import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Scanner; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.Connection.Method; import org.jsoup.Connection.Response; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements;public class moni {public static void main(String[] args) throws IOException {//Scanner sc=new Scanner(System.in);//test test=new test();String url="http://jwgl.just.edu.cn:8080/jsxsd/";Connection con=Jsoup.connect(url).timeout(30000);Response re=con.execute();Document doc=Jsoup.parse(re.body());Elements link=doc.select("form");Elements links=link.select("input");Map map = new HashMap<>();for(Element e:links){if(e.attr("name").equals("USERNAME")) {e.attr("value","162210702210"); }if(e.attr("name").equals("PASSWORD")) {e.attr("value","285511");}if(e.attr("name").length()>0) {map.put(e.attr("name"), e.attr("value"));} }//登陸部分Connection con2=Jsoup.connect(url "xk/LoginToXk").cookies(re.cookies()).timeout(2000);con2.data(map);con2.followRedirects(true); con2.method(Method.POST);Response re2=con2.execute();System.out.println("succss");// /* // * 登陸成功 // */String url3=url "xspj/xspj_find.do?Ves632DSdyV=NEW_XSD_JXPJ";Connection con3=Jsoup.connect(url3).timeout(2000);con3.header("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36");con3.header("Connection", "keep-alive");con3.cookies(re.cookies());Response res3=con3.ignoreContentType(true).method(Method.GET).execute();Document doc3=Jsoup.parse(res3.body());Elements elements=doc3.select("td a[href]");String shiyan="http://jwgl.just.edu.cn:8080" elements.get(0).attr("href");String lilun="http://jwgl.just.edu.cn:8080" elements.get(2).attr("href");judgle(shiyan,re.cookies());//實(shí)驗(yàn)課理論課評(píng)教judgle(lilun,re.cookies()); // System.out.println(shiyan); }private static void judgle(String url, Map cookies) throws IOException {// TODO 自動(dòng)生成的方法存根Document doc=Jsoup.connect(url).cookies(cookies).get();Elements elements=doc.select("td a[href]");ExecutorService ex= Executors.newFixedThreadPool(10);int i=0;for(Element e:elements){String judurl=e.attr("href");//javascript:JsMod('/js.................pe=view',1000,700)需要正則匹配//我直接用字符串切割String judur[]=judurl.split("'");judurl="http://jwgl.just.edu.cn:8080" judur[1];try {judThread judThread=new judThread(judurl, cookies);ex.execute(judThread);//judteacher(judurl,cookies); } catch (Exception e2) {System.out.println(e2);} }ex.shutdown();}static class judThread implements Runnable{String url;Mapcookies;public judThread(String url,Map map ) {this.url=url;this.cookies=map;}@Overridepublic void run() {// TODO Auto-generated method stubtry {judteacher(url, cookies);System.out.println(Thread.currentThread().getName() " jud" url);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}private static void judteacher(String judurl, Map cookies) throws IOException {// TODO 自動(dòng)生成的方法存根Document doc=Jsoup.connect(judurl).cookies(cookies).get();Elements link=doc.select("form");String actionurl="http://jwgl.just.edu.cn:8080" link.attr("action");Elements links=link.select("input");Mapmap=new TreeMap<>();for(Element e:links)//先處理所有隱藏的參數(shù){if(e.attr("type").equals("hidden")){map.put(e.attr("name"),e.attr("value"));}}Elements links2=link.select("#table1 tr");int index=0;//第一個(gè)不是參數(shù)for(Element e:links2)//處理button類元素{if(index==0) {index ;continue;}else if(index==links2.size()-1){String text=e.select("textarea").first().attr("name");map.put(text, "老師很認(rèn)真負(fù)責(zé)!");}else if(index==1) {Elements ele=e.select("input[type=radio]");Element NO2=ele.get(1);map.put(NO2.attr("name"), NO2.attr("value"));//System.out.println(NO2.attr("name"));}else {Elements ele=e.select("input[type=radio]");Element NO1=ele.get(0);map.put(NO1.attr("name"), NO1.attr("value"));//System.out.println(NO1.attr("name"));}index ;//System.out.println(e);}map.put("tj", "提 交");//最后提交form表單for(String a:map.keySet()){System.out.println(a " " map.get(a));}Mapmap2=new HashMap<>();Mapmap3=new HashMap<>();Mapmap4=new HashMap<>();Mapmap5=new HashMap<>();map.put("pj06xh", "1");map2.put("pj06xh", "2");map3.put("pj06xh", "3");map4.put("pj06xh", "4");map5.put("pj06xh", "5");map.put("issubmit", "1");Connection con4=Jsoup.connect(actionurl).cookies(cookies).timeout(2000);con4.data(map).data(map2).data(map3).data(map4).data(map5);con4.referrer(judurl);Response res4=con4.method(Method.POST).execute();} }python版本:
import requests from bs4 import BeautifulSoup import re def judteacher(url,cookiedict):res=requests.get(url,cookies=cookiedict)html=res.textsoup=BeautifulSoup(html,'lxml')form=soup.select('form')[0]actionurl='http://jwgl.just.edu.cn:8080'+form.get('action')#需要post提交的表單allinput=form.select('input')dictkey={}for link in allinput:if not str(link.get('type')).__eq__('button'):dictkey[str(link.get('name'))]=str(link.get('value'))buttoninput=form.select('#table1 tr')index=0for button in buttoninput:# print(index,button)if index==0:index+=1continueelif index==(buttoninput.__len__()-1):text=button.find('textarea').get('name')dictkey[text]='老師很負(fù)責(zé)任,收益良多'elif index==1:buttonselected=button.select('input[type=radio]')[1]dictkey[str(buttonselected.get('name'))]=str(buttonselected.get('value'))else:buttonselected = button.select('input[type=radio]')[0]dictkey[str(buttonselected.get('name'))] = str(buttonselected.get('value'))index+=1#第0個(gè)是沒用的,第一個(gè)是選滿意,剩下非常滿意,倒數(shù)第一個(gè)是文本評(píng)論dictkey['tj'] = '提 交'dictkey['pj06xh'] = ["1","2","3","4","5"]dictkey['issubmit']="1"post=requests.post(actionurl,data=dictkey,cookies=cookiedict)print(dictkey)def jud(url,cookiedict):res=requests.get(url,cookies=cookiedict)soup=BeautifulSoup(res.text,'lxml')teachers=soup.select('td a[href]')pattern=re.compile(r'.*[\'](.*)[\'].*')#正則提取javascrit:href='----'for teacherurl in teachers:teacherurl=str(teacherurl.get('href'))m=pattern.search(teacherurl)teacherurl='http://jwgl.just.edu.cn:8080'+str(m.group(1))#得到完整的teacherurltry:judteacher(teacherurl,cookiedict)except Exception as e:print(e) if __name__ == '__main__':url="http://jwgl.just.edu.cn:8080/jsxsd/"res=requests.get(url)cookiejar=res.cookiescookiedict=requests.utils.dict_from_cookiejar(cookiejar)html=res.textsoup=BeautifulSoup(html,'lxml')data={}inputkey=soup.select("input")for canshu in inputkey:if not str(canshu.get("name")).__eq__(None):data[str(canshu.get('name'))]=canshu.get('value')data['USERNAME']='162210702236'data['PASSWORD']='zhongad3344'# print(data)urlLogin=url+'xk/LoginToXk'res2=requests.post(urlLogin,data=data,cookies=cookiedict)url3=url+'xspj/xspj_find.do?Ves632DSdyV=NEW_XSD_JXPJ'res3=requests.get(url3,cookies=cookiedict)soup3=BeautifulSoup(res3.text,'lxml')hrefs=soup3.select("td a[href]")shiyan='http://jwgl.just.edu.cn:8080'+str(hrefs[0].get('href'))lilun='http://jwgl.just.edu.cn:8080'+str(hrefs[2].get('href'))jud(lilun,cookiedict)jud(shiyan,cookiedict)因?yàn)槭怯胘ava版本試水的,所以加了一些反爬措施,發(fā)現(xiàn)教務(wù)沒啥限制,py版本就簡寫了。另外,只要把第一個(gè)java改成函數(shù)式就可以融入ssm或者sb了。前端給個(gè)模板即可
由于時(shí)間和天氣惡劣,沒有寫太多具體步驟,如果有興趣可以一起研究探討,來年下次再用吧。。?。來年把線程池整進(jìn)去。
本人比較菜,代碼不足之處還請大佬指正。
如果對(duì)后端、爬蟲、數(shù)據(jù)結(jié)構(gòu)算法等感性趣歡迎關(guān)注我的個(gè)人公眾號(hào)交流:bigsai
總結(jié)
以上是生活随笔為你收集整理的模拟教务评教(强智教务)—一件评教实现原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python可视化文本分析(2)—sno
- 下一篇: Dungeon Master(三维bfs