模拟教务评教(强智教务)—一件评教实现原理
前言
- 前不久,学校有个校园帮助型app某某圈因为一件评教功能被教务批评了。现在有很多查成绩,查课程的app,他们的实现原理到底是啥了。这两天来到发小扬州这边,学习实现了这个功能,并且用java和python都写了一下,但是鉴于web端只会java,最后集成到springboot部署到服务器提供的小服务。
- 以前只知道这些东西是爬虫爬出来的,原本以为非常简单,自己研究了一下发现还是有很多的坑和坎。大致有一下几点:
- 模拟登陆,登陆是所有校园app要解决的第一难题,如果没验证码还好,但是如果有验证码解决思路有两个,抓包找图片手动打码,如果会点图像识别可以自己调算法,恰巧咱们科大有个不需要验证码的入口,在官网可以找到。
- 提交表单问题。在我的测试过程中遇到两点错误,第一就是正确提交表单后发现只提交一个按钮,这个原因是因为他有多个key-value是相同参数,也就是他有提交key-set内容。还有一个是提交可以完整提交但是只是保存没有真正提交,原因是他的js更改参数内容,需要修改,下面会介绍到。
- 异常处理,提交过的和没提交的表单内容有所不一致,需要进行异常处理保证程序可执行性,
- 当然写完了还发现一个问题就是速度有点慢的问题,我才发现没用多线程执行,算了算了,反正自己玩玩,就不加了。
步骤
用到的包:
java:jsoup
python:request,re,Beautifulsoup
-
下面开始介绍攻克的整个步骤(因为账号被测试用完无法给出更多fidder抓包图)
-
模拟登陆:
-
这部分算是简单的了,因为以前只是试过一些简单的模拟登陆。但是对一些session和cookie理解不够深刻。导致在这个地方 当时卡了很久。我原本以为是先请求登陆页面->带着这个页面的cookie和页面参数进行登陆->用返回界面的cookie进行操作。这个流程,实际上他第三部不会返回cookie,我当时以为那个地方出问题了 ,用fidder一直找不到问题。其实他将所有信息都存在session中,不过你执行的登陆的操作你的cookie的sessionid这个参数在服务器就是你的身份。
-
所以,你只需要模拟登陆拿着初始界面的cookie就可以完成所有操作了。根据图片和网页的form结构你可以发现只有两个参数。没有加密或者隐藏参数,直接怼就可以模拟登陆成功。
-
接着就要根据初始界面找到评教的链接,有实验课评教和理论课评教。然后就是找到各个老师的评教地址,这里他的地址有些不规则,要用正则或者切割获得,爬虫细节不做过多介绍
-
最后就是进入评教的表单
我这个是已经评教过的,没评教过的你会发现他有很多隐藏元素,还有就是一个button多个选项你要选一个,并且不能重复一样。就这样我遍历元素提交时候发现几个按钮只有最后一个提交成功,老师评价也成功,经过fidder抓参数和我控制台打印的参数几十个一一对比,发现他不是所有都是key-value,有的是key-set(图中画框的部分),在处理上java需要多加几组data的map,而python自带的字典支持各种形式可以直接用。 -
就这样,发现所有提交都有效,但是,只是达到保存效果,没有提交。通过抓包再次查看参数。查看原文代码会发现问题所在—js修改参数
-
这样你就发现问题所在,更改这个参数就可以提交成功。但是,会发现速度不快啊。。。原来忘记把线程池弄进来了。。哎,,算了,不想改代码了,清冷呵呵的。。附上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());//实验课理论课评教
judgle(lilun,re.cookies()); // System.out.println(shiyan);
}
private static void judgle(String url, Map cookies) throws IOException {
// TODO 自动生成的方法存根
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;
}
@Override
public void run() { // TODO Auto-generated method stub try { judteacher(url, cookies); System.out.println(Thread.currentThread().getName() " jud" url); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
} }
private static void judteacher(String judurl, Map cookies) throws IOException {
// TODO 自动生成的方法存根 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)//先处理所有隐藏的参数 { if(e.attr("type").equals("hidden")) { map.put(e.attr("name"),e.attr("value")); } } Elements links2=link.select("#table1 tr"); int index=0;//第一个不是参数 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, "老师很认真负责!"); } 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(); }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
python版本:
import requests
from bs4 import BeautifulSoup
import re
def judteacher(url,cookiedict): res=requests.get(url,cookies=cookiedict) html=res.text soup=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=0 for button in buttoninput: # print(index,button) if index==0: index+=1 continue elif index==(buttoninput.__len__()-1): text=button.find('textarea').get('name') dictkey[text]='老师很负责任,收益良多' 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个是没用的,第一个是选满意,剩下非常满意,倒数第一个是文本评论 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))#得到完整的teacherurl try: 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.cookies cookiedict=requests.utils.dict_from_cookiejar(cookiejar) html=res.text soup=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)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
因为是用java版本试水的,所以加了一些反爬措施,发现教务没啥限制,py版本就简写了。另外,只要把第一个java改成函数式就可以融入ssm或者sb了。前端给个模板即可
由于时间和天气恶劣,没有写太多具体步骤,如果有兴趣可以一起研究探讨,来年下次再用吧。。?。来年把线程池整进去。
本人比较菜,代码不足之处还请大佬指正。
如果对后端、爬虫、数据结构算法
等感性趣欢迎关注我的个人公众号交流:bigsai
文章来源: bigsai.blog.csdn.net,作者:Big sai,版权归原作者所有,如需转载,请联系作者。
原文链接:bigsai.blog.csdn.net/article/details/86516751
- 点赞
- 收藏
- 关注作者
评论(0)