├── .classpath ├── .gitignore ├── .project ├── .settings ├── .jsdtscope ├── com.genuitec.eclipse.migration.prefs ├── org.eclipse.jdt.core.prefs ├── org.eclipse.wst.common.component ├── org.eclipse.wst.common.project.facet.core.xml ├── org.eclipse.wst.jsdt.ui.superType.container └── org.eclipse.wst.jsdt.ui.superType.name ├── LICENSE ├── README.md ├── WebContent ├── META-INF │ └── MANIFEST.MF ├── WEB-INF │ ├── lib │ │ ├── commons-codec-1.9.jar │ │ ├── commons-logging-1.2.jar │ │ ├── gson-2.5.jar │ │ ├── httpclient-4.5.1.jar │ │ └── httpcore-4.4.3.jar │ └── web.xml └── test.jsp └── src ├── com └── guang │ └── jw │ ├── bean │ ├── Course.java │ └── Score.java │ ├── fliter │ └── EncodeFliter.java │ ├── servlet │ ├── JwServlet.java │ └── TestParm.java │ └── utils │ ├── JsonUtils.java │ └── JwUtils.java └── help.md /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .classpath -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | jw 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.jem.workbench.JavaEMFNature 31 | org.eclipse.wst.common.modulecore.ModuleCoreNature 32 | org.eclipse.wst.common.project.facet.core.nature 33 | org.eclipse.jdt.core.javanature 34 | org.eclipse.wst.jsdt.core.jsNature 35 | 36 | 37 | -------------------------------------------------------------------------------- /.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.settings/com.genuitec.eclipse.migration.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | performed.operation.correct.unbound.jre=1.0 3 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.compliance=1.7 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.source=1.7 8 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZFJW_API 2 | 原为广财教务系统非官方API(Java),现广财已换新系统,所以不能用在该校了,但可以通用于各高校正方教务系统,修改 `JwUtils.java` 里的 `url` 即可用在其他学校。 3 | 4 | 通过模拟登陆实现查分数、查课表、教学计划,若你想要在App、网站中实现查分则可用于服务器端,相比直接在客户端写这部分的好处是可控制。 5 | 6 | # USAGE 7 | - 各操作均需先登录,登陆用了教务的 `default2.aspx` 避开验证码。 8 | - 查成绩和课表分两种: 9 | 查当前学期成绩和查指定学期成绩,当前学期成绩是登陆后直接Get到的信息,比获取指定学期成绩更容易,对教务系统访问次数也更少。 10 | - 在客户端使用前可以先用`TestParm.java`(记得填学号密码)或者允许GET请求后浏览器测试下,相当于客户端 11 | - 修改代码前建议先看看 `src/help.md` 的说明 12 | 13 | **如需查课表给用户最好选择查课程介绍而不是直接查课表:** 14 | 15 | 1. 5,6,7节相同课这种情况在课程介绍里是一个项而在课表里却是两个项,选课程介绍方便给不同课程填充不同颜色。 16 | 2. 课程介绍在教务系统上先于课表公布 17 | 18 | 19 | ## 登陆 / 其他操作均需先登录 20 | 21 | POST http://localhost:8080/jw/main.do 22 | 参数 action=login&uname=学号&upwd=密码 23 | 24 | 返回 25 | 26 | 字符串:"登陆成功" or "登陆失败" 27 | 28 | ## 查当前学期课表 29 | 30 | POST http://localhost:8080/jw/main.do 31 | 参数 action=curSemesterKeBiao 32 | 33 | 返回Json数组格式的课表,注意type可能为空,因为教务系统中有些课是没有显示课程类型的 34 | 35 | [ 36 | { 37 | "name": "数据结构", 38 | "type": "必修", 39 | "time": "周一第1,2节{第1-16周}", 40 | "teacher": "Demo-匿名", 41 | "location": "拓新楼(SS1)135" 42 | }, 43 | { 44 | "name": "可视化程序设计", 45 | "type": "任选", 46 | "time": "周二第1,2节{第1-16周}", 47 | "teacher": "Demo-匿名1", 48 | "location": "励学楼(SJ1)401" 49 | }, 50 | { 51 | "name": "婚姻家庭纠纷法律实务", 52 | "type": "", 53 | "time": "周四第1,2节{第1-16周}", 54 | "teacher": "Demo-匿名2", 55 | "location": "拓新楼(SS1)335" 56 | } 57 | ] 58 | 59 | 失败则返回 60 | 61 | [] 62 | 63 | 可能是未登录,也可能是教务系统Hold不住了 64 | 65 | ## 查当前学期成绩 66 | 67 | POST http://localhost:8080/jw/main.do 68 | 参数 action=curSemesterScore 69 | 70 | 返回Json数组格式的成绩,包含学分、平时成绩、卷面成绩和总评 71 | 72 | [ 73 | { 74 | "courseName": "就业指导", 75 | "credit": "1.0", 76 | "regularScore": "85", 77 | "paperScore": "83", 78 | "totalScore": "84" 79 | }, 80 | { 81 | "courseName": "软件工程课程设计", 82 | "credit": "2.0", 83 | "regularScore": "97", 84 | "paperScore": "95", 85 | "totalScore": "96" 86 | } 87 | ] 88 | 89 | ## 查当前学期课程介绍 90 | 91 | POST http://localhost:8080/jw/main.do 92 | 参数 action=curSemesterJieShao 93 | 94 | 返回 95 | 96 | [ 97 | { 98 | "name": "形势与政策", 99 | "type": "必修", 100 | "time": "7,11,15(5,6)", 101 | "teacher": "匿名233", 102 | "location": "2-107" 103 | } 104 | ] 105 | 106 | ## 查指定学期课表 107 | 108 | POST http://localhost:8080/jw/main.do 109 | 参数 action=keBiao&xuenian=2014-2015&xueqi=1 110 | xuenian是学年,格式:20xx-20xx,有效参数:入学起的4年,如2013年入学,则2013-2014(大一)、2014-2015、2015-2016、2016-2017(大四) 111 | xueqi为学期,有效参数:1、2、全部 112 | 113 | 返回格式同查当前学期课表 114 | 115 | ## 查指定学期成绩 116 | 117 | POST http://localhost:8080/jw/main.do 118 | 参数 action=score&xuenian=2015-2016&xueqi=全部 119 | xuenian是学年,格式:20xx-20xx,有效参数:入学起的4年 120 | xueqi为学期,有效参数:1、2、全部 121 | 122 | 返回格式同查当前学期成绩 123 | 124 | # LICENSE 125 | 126 | **The MIT license** 127 | 128 | 该API可用于学习、发布查课表/成绩工具,可商用,但若被用作不正当用途,如利用用户的教务系统账号密码非法获取他人身份信息,造成的后果与原作者无关。 129 | 130 | -------------------------------------------------------------------------------- /WebContent/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | 4 | -------------------------------------------------------------------------------- /WebContent/WEB-INF/lib/commons-codec-1.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintercoder/ZFJW_API/a9e74b7b8733d66444127046ec2147cf77488f99/WebContent/WEB-INF/lib/commons-codec-1.9.jar -------------------------------------------------------------------------------- /WebContent/WEB-INF/lib/commons-logging-1.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintercoder/ZFJW_API/a9e74b7b8733d66444127046ec2147cf77488f99/WebContent/WEB-INF/lib/commons-logging-1.2.jar -------------------------------------------------------------------------------- /WebContent/WEB-INF/lib/gson-2.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintercoder/ZFJW_API/a9e74b7b8733d66444127046ec2147cf77488f99/WebContent/WEB-INF/lib/gson-2.5.jar -------------------------------------------------------------------------------- /WebContent/WEB-INF/lib/httpclient-4.5.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintercoder/ZFJW_API/a9e74b7b8733d66444127046ec2147cf77488f99/WebContent/WEB-INF/lib/httpclient-4.5.1.jar -------------------------------------------------------------------------------- /WebContent/WEB-INF/lib/httpcore-4.4.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintercoder/ZFJW_API/a9e74b7b8733d66444127046ec2147cf77488f99/WebContent/WEB-INF/lib/httpcore-4.4.3.jar -------------------------------------------------------------------------------- /WebContent/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | jw 4 | 5 | JwServlet 6 | com.guang.jw.servlet.JwServlet 7 | 8 | 9 | JwServlet 10 | /main.do 11 | 12 | 13 | 14 | TestParm 15 | com.guang.jw.servlet.TestParm 16 | 17 | 18 | TestParm 19 | /test.do 20 | 21 | 22 | 23 | test.jsp 24 | 25 | -------------------------------------------------------------------------------- /WebContent/test.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" 2 | session="false" pageEncoding="UTF-8"%> 3 | 4 | 5 | 6 | 7 | 恍恍惚惚教务处 8 | 9 | 20 | 21 | 22 | 23 |
24 | 25 | 本页面只供演示、测试时发post请求使用,实际使用请从客户端发送请求



26 |
27 | 28 | 30 | 31 | 33 | 35 |

36 | 38 |

39 | 40 | 42 |

44 | 46 |

47 | 48 | 49 |
50 | 51 | <% //返回的结果 52 | Object obj = request.getAttribute("result"); 53 | if( obj != null){ 54 | out.println(obj.toString() + "


"); 55 | } 56 | %> 57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /src/com/guang/jw/bean/Course.java: -------------------------------------------------------------------------------- 1 | package com.guang.jw.bean; 2 | 3 | public class Course { 4 | private String name; //课程名 5 | private String type; //课程类型:必修/任选等 6 | private String time; //上课时间 7 | private String teacher; //任课老师 8 | private String location; //教室 9 | 10 | public String getName() { 11 | return name; 12 | } 13 | 14 | public void setName(String name) { 15 | this.name = name; 16 | } 17 | 18 | public String getType() { 19 | return type; 20 | } 21 | 22 | public void setType(String type) { 23 | this.type = type; 24 | } 25 | 26 | public String getTime() { 27 | return time; 28 | } 29 | 30 | public void setTime(String time) { 31 | this.time = time; 32 | } 33 | 34 | public String getTeacher() { 35 | return teacher; 36 | } 37 | 38 | public void setTeacher(String teacher) { 39 | this.teacher = teacher; 40 | } 41 | 42 | public String getLocation() { 43 | return location; 44 | } 45 | 46 | public void setLocation(String location) { 47 | this.location = location; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/com/guang/jw/bean/Score.java: -------------------------------------------------------------------------------- 1 | package com.guang.jw.bean; 2 | 3 | //不含期中、实验成绩等 4 | public class Score { 5 | private String courseName; //课程名 6 | private String credit; //学分 7 | private String regularScore; //平时分 8 | private String paperScore; //期末卷面分 9 | private String totalScore; //总评 10 | 11 | public String getCredit() { 12 | return credit; 13 | } 14 | public void setCredit(String credit) { 15 | this.credit = credit; 16 | } 17 | public String getRegularScore() { 18 | return regularScore; 19 | } 20 | public void setRegularScore(String regularScore) { 21 | this.regularScore = regularScore; 22 | } 23 | public String getTotalScore() { 24 | return totalScore; 25 | } 26 | public void setTotalScore(String totalScore) { 27 | this.totalScore = totalScore; 28 | } 29 | public String getCourseName() { 30 | return courseName; 31 | } 32 | public void setCourseName(String courseName) { 33 | this.courseName = courseName; 34 | } 35 | public String getPaperScore() { 36 | return paperScore; 37 | } 38 | public void setPaperScore(String paperScore) { 39 | this.paperScore = paperScore; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/com/guang/jw/fliter/EncodeFliter.java: -------------------------------------------------------------------------------- 1 | package com.guang.jw.fliter; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.FilterConfig; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | import javax.servlet.annotation.WebFilter; 12 | import javax.servlet.annotation.WebInitParam; 13 | 14 | @WebFilter( 15 | filterName="EncodeFliter", 16 | urlPatterns="*", 17 | initParams={ 18 | @WebInitParam(name="input_encoding",value="UTF-8"), 19 | @WebInitParam(name="output_encoding",value="UTF-8") 20 | // @WebInitParam(name="output_encoding",value="gb2312") //教务系统返回的页面是gb2312 21 | 22 | } 23 | ) 24 | 25 | public class EncodeFliter implements Filter { 26 | private String input_encoding ; 27 | private String output_encoding ; 28 | 29 | public EncodeFliter() { 30 | } 31 | public void init(FilterConfig fConfig) throws ServletException { 32 | input_encoding = fConfig.getInitParameter("input_encoding"); 33 | output_encoding = fConfig.getInitParameter("output_encoding"); 34 | } 35 | 36 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 37 | request.setCharacterEncoding(input_encoding); 38 | response.setCharacterEncoding(output_encoding); 39 | chain.doFilter(request, response); 40 | } 41 | 42 | 43 | @Override 44 | public void destroy() { 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/com/guang/jw/servlet/JwServlet.java: -------------------------------------------------------------------------------- 1 | package com.guang.jw.servlet; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServlet; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | import com.guang.jw.utils.JsonUtils; 12 | import com.guang.jw.utils.JwUtils; 13 | 14 | /** 15 | * 服务器端后台逻辑处理页 16 | */ 17 | @SuppressWarnings("serial") 18 | public class JwServlet extends HttpServlet { 19 | 20 | @Override 21 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) 22 | throws ServletException, IOException { 23 | // this.doPost(req, resp); //TODO 测试用 24 | } 25 | 26 | protected void doPost(HttpServletRequest request, 27 | HttpServletResponse response) throws ServletException, IOException { 28 | Writer writer = response.getWriter(); 29 | boolean done = false; 30 | 31 | String action = request.getParameter("action"); 32 | String result = ""; 33 | 34 | if("login".equals(action)){ 35 | String sno = request.getParameter("uname"); 36 | String password = request.getParameter("upwd"); 37 | if(JwUtils.LoginToSystem(sno, password)){ 38 | request.getSession().setAttribute("sno", sno); 39 | result = "登陆成功"; 40 | }else{ 41 | result = "登陆失败"; 42 | } 43 | done = true; 44 | } 45 | else{ 46 | if( request.getSession().getAttribute("sno") == null){ 47 | writer.write("请登录"); 48 | return; 49 | } 50 | String sno = request.getSession().getAttribute("sno").toString(); 51 | switch (action) { 52 | case "curSemesterScore": 53 | String curScoreHtml = JwUtils.getCurSemesterScore(sno); 54 | result = JsonUtils.getJsonFromScore(curScoreHtml); 55 | done = true; 56 | break; 57 | case "curSemesterKeBiao": 58 | String curKeBiaoHtml = JwUtils.getCurSemesterKeBiao(sno); 59 | result = JsonUtils.getJsonFromKebiao(curKeBiaoHtml); 60 | done = true; 61 | break; 62 | case "curSemesterJieShao": 63 | String infoHtml = JwUtils.getCurSemesterJieShao(sno); 64 | result = JsonUtils.getJsonFromKebiao(infoHtml); 65 | done = true; 66 | break; 67 | } 68 | } 69 | 70 | if(done){ 71 | writer.write(result); 72 | return; 73 | } 74 | 75 | 76 | String xuenian = request.getParameter("xuenian"); 77 | String xueqi = request.getParameter("xueqi"); 78 | result = ""; 79 | String sno = request.getSession().getAttribute("sno").toString(); 80 | switch (action) { 81 | case "keBiao": 82 | String keBiaoHtml = JwUtils.getKebiao(sno, xuenian, xueqi); 83 | result = JsonUtils.getJsonFromKebiao(keBiaoHtml); 84 | break; 85 | case "score": 86 | String scoreHtml = JwUtils.getScore(sno, xuenian, xueqi); 87 | result = JsonUtils.getJsonFromScore(scoreHtml); 88 | break; 89 | default: 90 | break; 91 | } 92 | writer.write(result); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/com/guang/jw/servlet/TestParm.java: -------------------------------------------------------------------------------- 1 | package com.guang.jw.servlet; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import javax.servlet.RequestDispatcher; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | import org.apache.http.Consts; 14 | import org.apache.http.NameValuePair; 15 | import org.apache.http.client.ClientProtocolException; 16 | import org.apache.http.client.HttpClient; 17 | import org.apache.http.client.entity.UrlEncodedFormEntity; 18 | import org.apache.http.client.methods.HttpPost; 19 | import org.apache.http.impl.client.HttpClientBuilder; 20 | import org.apache.http.message.BasicNameValuePair; 21 | import org.apache.http.protocol.HTTP; 22 | import org.apache.http.util.EntityUtils; 23 | 24 | /** 25 | * 测试发请求用,相当于客户端 26 | */ 27 | public class TestParm extends HttpServlet { 28 | private final String url = "http://localhost:8080/jw/main.do"; 29 | private final String testSno = "1325110..."; 30 | private final String testPwd = ""; // TODO 用test.jsp测试的话改这里 31 | private final String testXuenian = "2014-2015"; 32 | private final String testXueqi = "1"; 33 | 34 | private static HttpClient httpclient; 35 | static { 36 | httpclient = HttpClientBuilder.create().build(); 37 | } 38 | 39 | protected void doGet(HttpServletRequest request, 40 | HttpServletResponse response) throws ServletException, IOException { 41 | doPost(request, response); 42 | } 43 | 44 | protected void doPost(HttpServletRequest request, 45 | HttpServletResponse response) throws ServletException, IOException { 46 | String action = request.getParameter("action"); 47 | String result = ""; 48 | switch (action) { 49 | case "login": 50 | result = testLogin(); 51 | break; 52 | case "curSemesterScore": 53 | result = testCurrentScore(); 54 | break; 55 | case "curSemesterKeBiao": 56 | result = testCurrentKebiao(); 57 | break; 58 | case "curSemesterJieShao": 59 | result = testCurrentJieShao(); 60 | break; 61 | case "keBiao": 62 | result = testKeBiao(); 63 | break; 64 | case "score": 65 | result = testScore(); 66 | break; 67 | default: 68 | break; 69 | } 70 | request.setAttribute("result", result); 71 | RequestDispatcher rdDispatcher = request 72 | .getRequestDispatcher("/test.jsp"); 73 | rdDispatcher.forward(request, response); 74 | } 75 | 76 | 77 | private String testLogin(){ 78 | HttpPost httpost = new HttpPost(url); 79 | List nvps = new ArrayList(); 80 | nvps.add(new BasicNameValuePair("action", "login")); 81 | nvps.add(new BasicNameValuePair("uname", testSno)); 82 | nvps.add(new BasicNameValuePair("upwd", testPwd)); 83 | httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); 84 | try { 85 | String result = EntityUtils.toString( httpclient.execute(httpost).getEntity(),HTTP.UTF_8); 86 | return result; 87 | } catch (ClientProtocolException e) { 88 | e.printStackTrace(); 89 | } catch (IOException e) { 90 | e.printStackTrace(); 91 | } 92 | return null; 93 | } 94 | 95 | private String testCurrentScore(){ 96 | HttpPost httpost = new HttpPost(url); 97 | List nvps = new ArrayList(); 98 | nvps.add(new BasicNameValuePair("action", "curSemesterScore")); 99 | nvps.add(new BasicNameValuePair("uname", testSno)); 100 | httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); 101 | try { 102 | String result = EntityUtils.toString( httpclient.execute(httpost).getEntity(),HTTP.UTF_8 ); 103 | return result; 104 | } catch (ClientProtocolException e) { 105 | e.printStackTrace(); 106 | } catch (IOException e) { 107 | e.printStackTrace(); 108 | } 109 | return null; 110 | } 111 | 112 | private String testCurrentKebiao(){ 113 | HttpPost httpost = new HttpPost(url); 114 | List nvps = new ArrayList(); 115 | nvps.add(new BasicNameValuePair("action", "curSemesterKeBiao")); 116 | nvps.add(new BasicNameValuePair("uname", testSno)); 117 | httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); 118 | try { 119 | String result = EntityUtils.toString( httpclient.execute(httpost).getEntity(),HTTP.UTF_8); 120 | return result; 121 | } catch (ClientProtocolException e) { 122 | e.printStackTrace(); 123 | } catch (IOException e) { 124 | e.printStackTrace(); 125 | } 126 | return null; 127 | } 128 | 129 | private String testCurrentJieShao() { 130 | HttpPost httpost = new HttpPost(url); 131 | List nvps = new ArrayList(); 132 | nvps.add(new BasicNameValuePair("action", "curSemesterJieShao")); 133 | nvps.add(new BasicNameValuePair("uname", testSno)); 134 | httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); 135 | try { 136 | String result = EntityUtils.toString( httpclient.execute(httpost).getEntity(),HTTP.UTF_8); 137 | return result; 138 | } catch (ClientProtocolException e) { 139 | e.printStackTrace(); 140 | } catch (IOException e) { 141 | e.printStackTrace(); 142 | } 143 | return null; 144 | } 145 | 146 | private String testScore(){ 147 | HttpPost httpost = new HttpPost(url); 148 | List nvps = new ArrayList(); 149 | nvps.add(new BasicNameValuePair("action", "score")); 150 | nvps.add(new BasicNameValuePair("uname", testSno)); 151 | nvps.add(new BasicNameValuePair("xuenian", testXuenian)); 152 | nvps.add(new BasicNameValuePair("xueqi", testXueqi)); 153 | httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); 154 | try { 155 | String result = EntityUtils.toString( httpclient.execute(httpost).getEntity(),HTTP.UTF_8); 156 | return result; 157 | } catch (ClientProtocolException e) { 158 | e.printStackTrace(); 159 | } catch (IOException e) { 160 | e.printStackTrace(); 161 | } 162 | return null; 163 | } 164 | private String testKeBiao(){ 165 | HttpPost httpost = new HttpPost(url); 166 | List nvps = new ArrayList(); 167 | nvps.add(new BasicNameValuePair("action", "keBiao")); 168 | nvps.add(new BasicNameValuePair("uname", testSno)); 169 | nvps.add(new BasicNameValuePair("xuenian", testXuenian)); 170 | nvps.add(new BasicNameValuePair("xueqi", testXueqi)); 171 | httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); 172 | try { 173 | String result = EntityUtils.toString( httpclient.execute(httpost).getEntity(),HTTP.UTF_8); 174 | return result; 175 | } catch (ClientProtocolException e) { 176 | e.printStackTrace(); 177 | } catch (IOException e) { 178 | e.printStackTrace(); 179 | } 180 | return null; 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /src/com/guang/jw/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.guang.jw.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | import com.google.gson.Gson; 9 | import com.guang.jw.bean.Course; 10 | import com.guang.jw.bean.Score; 11 | 12 | /** 13 | * 提取html页面中有用信息并转成json格式,用于返回给客户端 14 | * @author xiaoguang 15 | */ 16 | public class JsonUtils { 17 | private static Gson gson ; 18 | static{ 19 | gson = new Gson(); 20 | } 21 | 22 | /** 23 | * 解析课表页面,返回Json格式的核心数据,每个子项为bean/Course格式 24 | * @param kebiaoHtml 25 | * @return 26 | */ 27 | public static String getJsonFromKebiao(String kebiaoHtml) { 28 | List courses = new ArrayList<>(); 29 | String regex = " ].*?(.*?)(
.*?)"; 30 | Pattern pattern = Pattern.compile(regex); 31 | Matcher matcher = pattern.matcher(kebiaoHtml); 32 | while(matcher.find()){ 33 | Course course = new Course(); 34 | String gg[] = matcher.group(1).split("\">"); 35 | course.setName(gg[gg.length-1]); 36 | 37 | String content = matcher.group(2); 38 | String arg[] = content.split("
"); 39 | if(arg.length == 5){ 40 | course.setType(arg[1]); 41 | course.setTime(arg[2]); 42 | course.setTeacher(arg[3]); 43 | course.setLocation(arg[4]); 44 | }else{ 45 | course.setType(""); 46 | course.setTime(arg[1]); 47 | course.setTeacher(arg[2]); 48 | course.setLocation(arg[3]); 49 | } 50 | courses.add(course); 51 | } 52 | return gson.toJson(courses); 53 | } 54 | 55 | /** 56 | * 解析查分页面,返回Json格式的核心数据,每个子项为bean/Socre格式 57 | * @param scoreHtml 58 | * @return 59 | */ 60 | public static String getJsonFromScore(String scoreHtml) { 61 | List scores = new ArrayList<>(); 62 | String regex = "\\d{6}(.+?).+?(\\d\\.\\d)(\\d+).+?(\\d+).+?(\\d+)"; 63 | 64 | Pattern pattern = Pattern.compile(regex); 65 | Matcher matcher = pattern.matcher(scoreHtml); 66 | while(matcher.find()){ 67 | Score score = new Score(); 68 | score.setCourseName(matcher.group(1)); 69 | score.setCredit(matcher.group(2)); 70 | score.setRegularScore(matcher.group(3)); 71 | score.setPaperScore(matcher.group(4)); 72 | score.setTotalScore(matcher.group(5)); 73 | scores.add(score); 74 | } 75 | return gson.toJson(scores); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/com/guang/jw/utils/JwUtils.java: -------------------------------------------------------------------------------- 1 | package com.guang.jw.utils; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.io.UnsupportedEncodingException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | 12 | import org.apache.http.Consts; 13 | import org.apache.http.Header; 14 | import org.apache.http.HttpResponse; 15 | import org.apache.http.NameValuePair; 16 | import org.apache.http.client.ClientProtocolException; 17 | import org.apache.http.client.HttpClient; 18 | import org.apache.http.client.config.RequestConfig; 19 | import org.apache.http.client.entity.UrlEncodedFormEntity; 20 | import org.apache.http.client.methods.HttpGet; 21 | import org.apache.http.client.methods.HttpPost; 22 | import org.apache.http.impl.client.CloseableHttpClient; 23 | import org.apache.http.impl.client.HttpClientBuilder; 24 | import org.apache.http.message.BasicNameValuePair; 25 | import org.apache.http.util.EntityUtils; 26 | 27 | /** 28 | * 从教务处网站 获取信息的工具类,返回html代码 29 | * 查成绩和课表需要先获取页面的ViewState,一切需先登录 30 | */ 31 | public class JwUtils { 32 | private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"; 33 | private static final String Base_Referer = "http://jwc.gdufe.edu.cn/"; 34 | private static final String Jw_Host = "http://jwxt2.gdufe.edu.cn:8080"; 35 | 36 | //下面这些URL要根据Base_URL刷新 37 | private static String Base_URL = "http://jwxt2.gdufe.edu.cn:8080/(S(100000000000000000000002))"; 38 | private static String Login_URL = Base_URL + "/default2.aspx"; 39 | private static String LOGIN_URL_NO_Verify = Base_URL + "/default_ysdx.aspx"; 40 | private static String Referer = Base_URL + "/xs_main.aspx?xh=";// + sno; //登陆后的reference 41 | private static String Score_URL = Base_URL + "/xscjcx_dq.aspx?xh="; 42 | private static String KeBiao_URL = Base_URL + "/xskbcx.aspx?xh="; 43 | private static String KeChengJieShao_URL = Base_URL + "/tjkbcx.aspx?xh="; 44 | 45 | private static String VIEW_STATE = ""; 46 | private static String EVENT_STATE = ""; 47 | 48 | private static HttpClient httpclient; 49 | private static String encoding = "gb2312"; 50 | 51 | static { 52 | httpclient = HttpClientBuilder.create().build(); 53 | } 54 | 55 | /** 56 | * 登陆教务系统,成功返回true,失败返回false 57 | */ 58 | public static boolean LoginToSystem(String sno, String password) { 59 | if(!getAndSetBaseUrl(Jw_Host)){//教务系统崩溃 60 | return false; 61 | }else{ 62 | refreshUrlByBaseUrl(); 63 | getAndSetViewState(Login_URL,Base_Referer); 64 | if(LoginToSystem(Login_URL, sno, password) ){ 65 | return true; 66 | }else{ 67 | return false; 68 | } 69 | } 70 | } 71 | public static String getCurSemesterScore(String sno) { 72 | return getCurSemesterInfo(Score_URL,sno); 73 | } 74 | public static String getCurSemesterKeBiao(String sno) { 75 | return getCurSemesterInfo(KeBiao_URL,sno); 76 | } 77 | public static String getCurSemesterJieShao(String sno) { 78 | return getCurSemesterInfo(KeChengJieShao_URL,sno); 79 | } 80 | /** 81 | * 获取指定学期课表 82 | * @param sno 学号 83 | * @param xuenian 学年 example:2015-2016 84 | * @param xueqi 学期 example:2 85 | * @return 86 | */ 87 | public static String getKebiao(String sno, String xuenian, String xueqi) { 88 | getAndSetViewState(KeBiao_URL + sno ,Referer + sno); 89 | return getKebiao(KeBiao_URL, sno, xuenian, xueqi); 90 | } 91 | /** 92 | * 查分,提供学号和学年、学期 93 | * @param sno 学号 94 | * @param xuenian 学年,2015-2016格式 或者 全部 95 | * @param xueqi 学期,1 或 2 或者 全部 96 | * @return html,([^<>]+) 可以过滤无关html信息,再进一步过滤科目分数等。
97 | * \d{6}[\r\n](.*)[\r\n].*[\r\n].*[\r\n](\d\.\d)过滤科目名、学分,具体分数的没写 98 | */ 99 | public static String getScore(String sno, String xuenian, String xueqi) { 100 | getAndSetViewState(Score_URL + sno ,Referer + sno); 101 | return getScore(Score_URL, sno, xuenian, xueqi); 102 | } 103 | 104 | 105 | 106 | /** 107 | * 当BaseUrl改变后刷新相关的Url,但不附加学号 108 | */ 109 | private static void refreshUrlByBaseUrl() { 110 | Login_URL = Base_URL + "/default2.aspx"; 111 | LOGIN_URL_NO_Verify = Base_URL + "/default_ysdx.aspx"; 112 | Referer = Base_URL + "/xs_main.aspx?xh=";// + sno; //登陆后的reference 113 | Score_URL = Base_URL + "/xscjcx_dq.aspx?xh="; 114 | KeBiao_URL = Base_URL + "/xskbcx.aspx?xh="; 115 | KeChengJieShao_URL = Base_URL + "/tjkbcx.aspx?xh="; 116 | } 117 | /** 118 | * 获取隐藏的__VIEWSTATE和__EVENTVALIDATION属性,用于获取当前页面的信息。
119 | * 在 登陆 查课表 查分 前需要调用获取对应的默认视图__VIEWSTATE 120 | */ 121 | private static void getAndSetViewState(String url,String referer) { 122 | HttpGet httpGet = new HttpGet(url); 123 | try { 124 | httpGet.setHeader("User-Agent", USER_AGENT); 125 | httpGet.setHeader("Referer", referer); 126 | HttpResponse httpResponse = httpclient.execute(httpGet); 127 | BufferedReader rd = new BufferedReader(new InputStreamReader( 128 | httpResponse.getEntity().getContent(), encoding)); 129 | StringBuffer result = new StringBuffer(); 130 | String line = ""; 131 | while ((line = rd.readLine()) != null) { 132 | result.append(line); 133 | } 134 | String pattern1 = "__VIEWSTATE\" value=\"(.*?)\" />"; 135 | String pattern2 = "__EVENTVALIDATION\" value=\"(.*?)\" />"; 136 | Pattern r1 = Pattern.compile(pattern1); 137 | Pattern r2 = Pattern.compile(pattern2); 138 | Matcher m1 = r1.matcher(result); 139 | Matcher m2 = r2.matcher(result); 140 | if (m1.find()) { 141 | VIEW_STATE = m1.group(1); 142 | } 143 | if (m2.find()) { 144 | EVENT_STATE = m2.group(1); 145 | } 146 | } catch (Exception e) { 147 | e.printStackTrace(); 148 | } 149 | } 150 | /** 151 | * 访问一次Jw_Host,根据返回信息获取当前正确sessionId,写回BaseUrl
152 | * 注意不能是访问带有具体sessionId的链接,否则第一次获取成功,之后一段时间就返回200登陆了
153 | * 貌似是因为如果带有sessionId的话即使访问其他sessionId也被认为这个客户端ip登陆成功,新旧sessionId都有效
154 | * @param url Jw_Host,直接填地址+端口,不能带sessionId 155 | * @param sno 156 | * @param password 157 | */ 158 | private static boolean getAndSetBaseUrl(String url) { 159 | CloseableHttpClient client = HttpClientBuilder.create().build(); //只用一次,选择可close的 160 | HttpGet get = new HttpGet(url); 161 | RequestConfig requestConfig = RequestConfig.custom().setRedirectsEnabled(false).build(); 162 | get.setConfig(requestConfig); //禁止自动跳转,方便获取header的跳转信息 163 | HttpResponse response; 164 | try { 165 | response = client.execute(get); 166 | Header header = response.getFirstHeader("Location");//header => [Location: /(S(mabs01f0sjr3jo45gy4atk55))/default2.aspx] 167 | int statuCode = response.getStatusLine().getStatusCode(); 168 | if (statuCode == 302) { //跳转情况,到我们要的url 169 | String sessionId = header.getValue().replace("/default2.aspx", ""); //sessionId => [/(S(mgg3q5fvspor3o2xlady0g45))] 170 | Base_URL = Jw_Host + sessionId; //设置正确的Base_URL 171 | client.close(); 172 | return true; 173 | }else{ //教务系统崩溃 174 | System.out.println("header="+header +" statu="+statuCode); 175 | client.close(); 176 | return false; 177 | } 178 | } catch (ClientProtocolException e) { 179 | e.printStackTrace(); 180 | } catch (IOException e) { 181 | e.printStackTrace(); 182 | } 183 | return true; 184 | } 185 | 186 | /** 187 | * 实际的登陆教务系统代码,主要是获取Cookie,之后httpClient自动管理Cookie,需在getViewState()后调用
188 | */ 189 | private static boolean LoginToSystem(String url, String sno, String password) { 190 | HttpPost httpost = new HttpPost(url); 191 | httpost.setHeader("Referer", Base_Referer); 192 | httpost.setHeader("User-Agent", USER_AGENT); 193 | List nvps = new ArrayList(); 194 | nvps.add(new BasicNameValuePair("__VIEWSTATE", VIEW_STATE)); 195 | nvps.add(new BasicNameValuePair("__EVENTVALIDATION", EVENT_STATE)); 196 | nvps.add(new BasicNameValuePair("txtUserName", sno)); 197 | nvps.add(new BasicNameValuePair("TextBox2", password)); 198 | nvps.add(new BasicNameValuePair("txtSecretCode", "")); 199 | nvps.add(new BasicNameValuePair("RadioButtonList1", "%D1%A7%C9%FA")); 200 | nvps.add(new BasicNameValuePair("Button1", "")); 201 | nvps.add(new BasicNameValuePair("lbLanguage", "")); 202 | httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); 203 | 204 | HttpResponse response; 205 | try { 206 | response = httpclient.execute(httpost); 207 | // String result = EntityUtils.toString(response.getEntity()); 208 | /* 登陆成功后会返回302跳转,登陆失败则是200返回错误信息 */ 209 | int statuCode = response.getStatusLine().getStatusCode(); 210 | if (statuCode == 302) { 211 | return true; 212 | } else { 213 | return false; 214 | } 215 | } catch (ClientProtocolException e) { 216 | e.printStackTrace(); 217 | } catch (IOException e) { 218 | e.printStackTrace(); 219 | } 220 | return false; 221 | } 222 | 223 | /** 224 | * 无验证码的登陆链接,也可以用 225 | * @param url LOGIN_URL_NO_Verify 226 | * @param sno 227 | * @param password 228 | * @return 229 | */ 230 | private boolean LoginToSystemNoVerify(String url, String sno, String password) { 231 | HttpPost httpost = new HttpPost(url); 232 | httpost.setHeader("Referer", Base_Referer); 233 | httpost.setHeader("User-Agent", USER_AGENT); 234 | List nvps = new ArrayList(); 235 | nvps.add(new BasicNameValuePair("__VIEWSTATE", VIEW_STATE)); 236 | nvps.add(new BasicNameValuePair("__EVENTVALIDATION", EVENT_STATE)); 237 | nvps.add(new BasicNameValuePair("TextBox1", sno)); 238 | nvps.add(new BasicNameValuePair("TextBox2", password)); 239 | nvps.add(new BasicNameValuePair("RadioButtonList1", "%D1%A7%C9%FA")); 240 | nvps.add(new BasicNameValuePair("Button1", "")); 241 | httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); 242 | 243 | HttpResponse response; 244 | try { 245 | response = httpclient.execute(httpost); 246 | int statuCode = response.getStatusLine().getStatusCode(); 247 | if (statuCode == 302) { 248 | return true; 249 | } else { 250 | return false; 251 | } 252 | } catch (ClientProtocolException e) { 253 | e.printStackTrace(); 254 | } catch (IOException e) { 255 | e.printStackTrace(); 256 | } 257 | return false; 258 | } 259 | 260 | /** 261 | * 直接GET方式访问带学号的链接
262 | * 可获取当前学期课表、当前学期成绩、课程介绍
263 | * 传入KeBiao_URL 获取当前学期课表
264 | * 传入Score_UR 获取当前学期成绩
265 | * 传入KeChengJieShao_URL 获取课程介绍
266 | */ 267 | private static String getCurSemesterInfo(String url, String sno) { 268 | HttpGet httpGet = new HttpGet(url + sno); 269 | httpGet.setHeader("User-Agent", USER_AGENT); 270 | httpGet.setHeader("Referer", Referer + sno); 271 | HttpResponse httpResponse; 272 | String result = ""; 273 | try { 274 | httpResponse = httpclient.execute(httpGet); 275 | result = EntityUtils.toString(httpResponse.getEntity()); 276 | } catch (Exception e) { 277 | e.printStackTrace(); 278 | } 279 | return result.toString(); 280 | } 281 | private static String getKebiao(String url,String sno, String xuenian, String xueqi) { 282 | HttpPost httpost = new HttpPost(url+sno); 283 | httpost.setHeader("User-Agent", USER_AGENT); 284 | httpost.setHeader("Referer", url+sno); //当前学生查询课表的get链接,[&xm=%u97e9%u88d5%u5149&gnmkdm=N121603]这部分不需要 285 | List nvps = new ArrayList(); 286 | 287 | nvps.add(new BasicNameValuePair("__EVENTTARGET", "xqd")); 288 | nvps.add(new BasicNameValuePair("__EVENTARGUMENT", "")); 289 | nvps.add(new BasicNameValuePair("__LASTFOCUS", "")); 290 | nvps.add(new BasicNameValuePair("__VIEWSTATE", VIEW_STATE)); 291 | nvps.add(new BasicNameValuePair("__EVENTVALIDATION", EVENT_STATE)); 292 | 293 | nvps.add(new BasicNameValuePair("xnd", xuenian)); 294 | nvps.add(new BasicNameValuePair("xqd", xueqi)); 295 | try { 296 | httpost.setEntity(new UrlEncodedFormEntity(nvps, "GBK")); 297 | } catch (UnsupportedEncodingException e1) { 298 | e1.printStackTrace(); 299 | } 300 | HttpResponse response; 301 | try { 302 | response = httpclient.execute(httpost); 303 | String result = EntityUtils.toString(response.getEntity()); 304 | return result; 305 | } catch (Exception e) { 306 | e.printStackTrace(); 307 | } 308 | return ""; 309 | } 310 | 311 | private static String getScore(String url,String sno, String xuenian, String xueqi) { 312 | HttpPost httpost = new HttpPost(url+sno); 313 | httpost.setHeader("User-Agent", USER_AGENT); 314 | httpost.setHeader("Referer", url+sno); //当前学生查询成绩的get链接 315 | List nvps = new ArrayList(); 316 | 317 | nvps.add(new BasicNameValuePair("__EVENTTARGET", "ddlxn")); 318 | nvps.add(new BasicNameValuePair("__EVENTARGUMENT", "")); 319 | nvps.add(new BasicNameValuePair("__LASTFOCUS", "")); 320 | nvps.add(new BasicNameValuePair("__VIEWSTATE", VIEW_STATE)); 321 | nvps.add(new BasicNameValuePair("__EVENTVALIDATION", EVENT_STATE)); 322 | 323 | nvps.add(new BasicNameValuePair("ddlxn", xuenian)); 324 | nvps.add(new BasicNameValuePair("ddlxq", xueqi)); 325 | nvps.add(new BasicNameValuePair("btnCx", "+%B2%E9++%D1%AF+")); 326 | try { 327 | httpost.setEntity(new UrlEncodedFormEntity(nvps, "GBK")); 328 | } catch (UnsupportedEncodingException e1) { 329 | e1.printStackTrace(); 330 | } 331 | 332 | HttpResponse response; 333 | try { 334 | response = httpclient.execute(httpost); 335 | String result = EntityUtils.toString(response.getEntity()); 336 | return result; 337 | } catch (Exception e) { 338 | e.printStackTrace(); 339 | } 340 | return ""; 341 | } 342 | } 343 | -------------------------------------------------------------------------------- /src/help.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 1. 教务系统登陆页地址的`(S(hpuxisy320bpi2iunqzwd445))/`下称为cookieId,是系统为了防止浏览器禁用Cookie而存在URL上的,每次都会变化,一段时间后失效。 3 | 4 | 所以sessionId需要每次登陆前获取,获取方式:Get请求[http://jwxt2.gdufe.edu.cn:8080](http://jwxt2.gdufe.edu.cn:8080)会返回302跳转,header里的`location`有跳转链接,内含sessionId,需要禁止自动跳转才能获取。 5 | 6 | 有sessionId之后登陆并用Cookie进行其他操作,全程同一个HttpClient对象会自动管理Cookie(4.x版本HttpClient) 7 | 8 | 2. 登陆前需要获取一次登陆页的`__VIEWSTATE`信息,__VIEWSTATE存储了当前视图结构,表示当前页面有什么东西,编码转换地址:[http://viewstatedecoder.azurewebsites.net/](http://viewstatedecoder.azurewebsites.net/) 9 | 10 | 3. 登陆后可以直接GET查当前学期课表、分数等,需要指定学期的话要获取当前学期课表/分数页面的__VIEWSTATE,再Post过去。 11 | 12 | 4. 登陆后基本上所有请求都含`xh=...&xm=...&gnmkdm=N121603`,xm是GBK/gb2312编码的姓名,gnmkdm固定值,这2个不是必要属性。 13 | 14 | 5. 代码中的成员变量URL均不包含学号,所以除登陆时外,`getAndSetViewState()`的url需带上学号。 15 | 16 | 6. `Base_URL`有改变的话(登陆时获取sessionId之后就改变)需要调用refreshUrlByBaseUrl()更新相关的URL。 17 | 18 | # 特殊情况 19 | 20 | 如果从课表html里正则匹配课程时不对劲,则可能是这种情况 21 | 22 | 第3节人工智能基础
必修
1-16(3)
李某
4-110
创业基础
必修
1-16(3,4)
何某人
2-203
 计算机图形学
1-16(3,4)
某A
4-205
    23 | 24 | 第4节      25 | 26 | 下午第5节 形势与政策
必修
7,11,15(5,6)
某B
2-107
27 | 28 | --------------------------------------------------------------------------------