parent
b78577fc28
commit
efab489d17
@ -1,4 +1,14 @@ |
||||
package cn.linghang.mywust.core.exception; |
||||
|
||||
public class BasicException extends Exception { |
||||
public BasicException() { |
||||
} |
||||
|
||||
public BasicException(String message) { |
||||
super(message); |
||||
} |
||||
|
||||
public BasicException(String message, Throwable cause) { |
||||
super(message, cause); |
||||
} |
||||
} |
||||
|
@ -1,4 +1,14 @@ |
||||
package cn.linghang.mywust.core.exception; |
||||
|
||||
public class CookieInvalidException extends BasicException { |
||||
public CookieInvalidException() { |
||||
} |
||||
|
||||
public CookieInvalidException(String message) { |
||||
super(message); |
||||
} |
||||
|
||||
public CookieInvalidException(String message, Throwable cause) { |
||||
super(message, cause); |
||||
} |
||||
} |
||||
|
@ -1,4 +1,15 @@ |
||||
package cn.linghang.mywust.core.exception; |
||||
|
||||
public class ParseException extends BasicException { |
||||
public ParseException() { |
||||
super("解析数据失败"); |
||||
} |
||||
|
||||
public ParseException(String message) { |
||||
super(message); |
||||
} |
||||
|
||||
public ParseException(String message, Throwable cause) { |
||||
super(message, cause); |
||||
} |
||||
} |
||||
|
@ -1,4 +1,14 @@ |
||||
package cn.linghang.mywust.core.exception; |
||||
|
||||
public class PasswordWornException extends BasicException { |
||||
public PasswordWornException() { |
||||
} |
||||
|
||||
public PasswordWornException(String message) { |
||||
super(message); |
||||
} |
||||
|
||||
public PasswordWornException(String message, Throwable cause) { |
||||
super(message, cause); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,57 @@ |
||||
package cn.linghang.mywust.core.parser.undergraduate; |
||||
|
||||
import cn.linghang.mywust.core.exception.ParseException; |
||||
import cn.linghang.mywust.core.parser.Parser; |
||||
import cn.linghang.mywust.core.parser.undergraduate.xpath.ExamInfoXpath; |
||||
import cn.linghang.mywust.model.undergrade.ExamInfo; |
||||
import org.jsoup.Jsoup; |
||||
import org.jsoup.select.Elements; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class ExamInfoParser implements Parser<List<ExamInfo>> { |
||||
private static final Logger log = LoggerFactory.getLogger(ExamInfoParser.class); |
||||
|
||||
@Override |
||||
public List<ExamInfo> parse(String html) throws ParseException { |
||||
Elements rows = Jsoup.parse(html).selectXpath(ExamInfoXpath.EXAM_INFO_ROWS_XPATH); |
||||
if (rows.isEmpty()) { |
||||
throw new ParseException(); |
||||
} |
||||
|
||||
List<ExamInfo> examInfos = new ArrayList<>(rows.size()); |
||||
|
||||
try { |
||||
for (int i = 1; i < rows.size(); i++) { |
||||
Elements columns = rows.get(i).getElementsByTag("td"); |
||||
|
||||
ExamInfo examInfo = new ExamInfo(); |
||||
|
||||
// 这段看着震撼,但其实很丑
|
||||
examInfo.setId(columns.get(0).text()); |
||||
examInfo.setTerm(columns.get(1).text()); |
||||
examInfo.setCourseNumber(columns.get(2).text()); |
||||
examInfo.setCourseName(columns.get(3).text()); |
||||
examInfo.setGroupName(columns.get(4).text()); |
||||
examInfo.setScore(columns.get(5).text()); |
||||
examInfo.setFlag(columns.get(6).text()); |
||||
examInfo.setCredit(columns.get(7).text()); |
||||
examInfo.setCourseHours(columns.get(8).text()); |
||||
examInfo.setGradePoint(columns.get(9).text()); |
||||
examInfo.setEvaluateMethod(columns.get(11).text()); |
||||
examInfo.setKind(columns.get(12).text()); |
||||
examInfo.setCourseKind(columns.get(13).text()); |
||||
|
||||
examInfos.add(examInfo); |
||||
} |
||||
} catch (Exception e) { |
||||
log.warn("解析成绩页面时发生错误:{}", e.getMessage()); |
||||
log.warn("终止解析,返回已解析数据"); |
||||
} |
||||
|
||||
return examInfos; |
||||
} |
||||
} |
@ -0,0 +1,19 @@ |
||||
package cn.linghang.mywust.core.parser.undergraduate; |
||||
|
||||
import cn.linghang.mywust.core.exception.ParseException; |
||||
import cn.linghang.mywust.core.parser.Parser; |
||||
import org.jsoup.Jsoup; |
||||
import org.jsoup.nodes.Element; |
||||
|
||||
public class SchemePageParser implements Parser<String> { |
||||
|
||||
@Override |
||||
public String parse(String html) throws ParseException { |
||||
Element schemeElement = Jsoup.parse(html).getElementById("dataList"); |
||||
if (schemeElement == null) { |
||||
throw new ParseException("教学方案html解析提取失败,id为dataList的元素不存在"); |
||||
} |
||||
|
||||
return schemeElement.outerHtml(); |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
package cn.linghang.mywust.core.parser.undergraduate.xpath; |
||||
|
||||
public class ExamInfoXpath { |
||||
public static final String EXAM_INFO_ROWS_XPATH = "//*[@id=\"dataList\"]/tbody/tr"; |
||||
} |
@ -0,0 +1,50 @@ |
||||
package cn.linghang.mywust.core.service.undergraduate; |
||||
|
||||
import cn.linghang.mywust.core.exception.CookieInvalidException; |
||||
import cn.linghang.mywust.core.exception.ParseException; |
||||
import cn.linghang.mywust.core.parser.undergraduate.ExamInfoParser; |
||||
import cn.linghang.mywust.core.request.BkjxRequestFactory; |
||||
import cn.linghang.mywust.core.util.BkjxUtil; |
||||
import cn.linghang.mywust.model.undergrade.ExamInfo; |
||||
import cn.linghang.mywust.network.RequestClientOption; |
||||
import cn.linghang.mywust.network.Requester; |
||||
import cn.linghang.mywust.network.entitys.HttpRequest; |
||||
import cn.linghang.mywust.network.entitys.HttpResponse; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
public class ExamInfoApi { |
||||
private static final Logger log = LoggerFactory.getLogger(ExamInfoApi.class); |
||||
|
||||
private final Requester requester; |
||||
|
||||
private static final ExamInfoParser parser = new ExamInfoParser(); |
||||
|
||||
public ExamInfoApi(Requester requester) { |
||||
this.requester = requester; |
||||
} |
||||
|
||||
public String getExamInfoPage(String cookies, RequestClientOption requestClientOption) throws IOException, CookieInvalidException { |
||||
HttpRequest request = BkjxRequestFactory.examScoreInfoRequest(cookies, "", "", ""); |
||||
HttpResponse response = requester.post(request, requestClientOption); |
||||
|
||||
// 检查响应是否正确
|
||||
if (response.getBody() == null || |
||||
response.getStatusCode() != HttpResponse.HTTP_OK || |
||||
BkjxUtil.checkLoginFinger(response.getBody())) { |
||||
|
||||
throw new CookieInvalidException("[请求获取成绩]:Cookie无效:" + cookies); |
||||
} |
||||
|
||||
return new String(response.getBody()); |
||||
} |
||||
|
||||
public List<ExamInfo> getExamInfo(String cookies, RequestClientOption requestClientOption) throws IOException, CookieInvalidException, ParseException { |
||||
String examInfoPage = this.getExamInfoPage(cookies, requestClientOption); |
||||
|
||||
return parser.parse(examInfoPage); |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
package cn.linghang.mywust.core.service.undergraduate; |
||||
|
||||
import cn.linghang.mywust.core.exception.CookieInvalidException; |
||||
import cn.linghang.mywust.core.exception.ParseException; |
||||
import cn.linghang.mywust.core.parser.undergraduate.SchemePageParser; |
||||
import cn.linghang.mywust.core.request.BkjxRequestFactory; |
||||
import cn.linghang.mywust.core.util.BkjxUtil; |
||||
import cn.linghang.mywust.network.RequestClientOption; |
||||
import cn.linghang.mywust.network.Requester; |
||||
import cn.linghang.mywust.network.entitys.HttpRequest; |
||||
import cn.linghang.mywust.network.entitys.HttpResponse; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class SchemeApi { |
||||
private final Requester requester; |
||||
|
||||
private static final SchemePageParser parser = new SchemePageParser(); |
||||
|
||||
public SchemeApi(Requester requester) { |
||||
this.requester = requester; |
||||
} |
||||
|
||||
public String getSchemePage(String cookies, RequestClientOption requestClientOption) throws CookieInvalidException, IOException { |
||||
HttpRequest request = BkjxRequestFactory.schemePageRequest(cookies); |
||||
HttpResponse response = requester.get(request, requestClientOption); |
||||
|
||||
// 检查响应是否正确
|
||||
if (response.getBody() == null || |
||||
response.getStatusCode() != HttpResponse.HTTP_OK || |
||||
BkjxUtil.checkLoginFinger(response.getBody())) { |
||||
|
||||
throw new CookieInvalidException("[请求获取成绩]:Cookie无效:" + cookies); |
||||
} |
||||
|
||||
return new String(response.getBody()); |
||||
} |
||||
|
||||
public String getPrueSchemePage(String cookies, RequestClientOption requestClientOption) throws IOException, CookieInvalidException, ParseException { |
||||
String fullPage = this.getSchemePage(cookies, requestClientOption); |
||||
return parser.parse(fullPage); |
||||
} |
||||
} |
@ -0,0 +1,88 @@ |
||||
package cn.linghang.mywust.model.undergrade; |
||||
|
||||
import lombok.AllArgsConstructor; |
||||
import lombok.Builder; |
||||
import lombok.Data; |
||||
import lombok.NoArgsConstructor; |
||||
|
||||
/** |
||||
* <p>考试成绩信息实体类</p> |
||||
* <br> |
||||
* <p>一个对象实体对应着一次考试,也就是系统里边看到的一行成绩</p> |
||||
* <p>决定全都用string存储,交给上层调用者自行处理转换</p> |
||||
* <p>看似浪费内存,但实际上解析出来的就是string,string转int/float然后又转成其他的什么后其实是更耗内存的</p> |
||||
* <p>既然如此不如直接存解析出来的值,具体如何使用就交给上层自行决定</p> |
||||
* |
||||
* @author lensfrex |
||||
* @created 2022-10-26 14:29 |
||||
*/ |
||||
@Data |
||||
@Builder |
||||
@NoArgsConstructor |
||||
@AllArgsConstructor |
||||
public class ExamInfo { |
||||
/** |
||||
* 序号id,在某些场景下可能会有用 |
||||
*/ |
||||
private String id; |
||||
|
||||
/** |
||||
* 学期 |
||||
*/ |
||||
private String term; |
||||
|
||||
/** |
||||
* 课程编号 |
||||
*/ |
||||
private String courseNumber; |
||||
|
||||
/** |
||||
* 课程名称 |
||||
*/ |
||||
private String courseName; |
||||
|
||||
/** |
||||
* 分组名 |
||||
*/ |
||||
private String groupName; |
||||
|
||||
/** |
||||
* 成绩 |
||||
*/ |
||||
private String score; |
||||
|
||||
/** |
||||
* 成绩标识(缺考) |
||||
*/ |
||||
private String flag; |
||||
|
||||
/** |
||||
* 学分 |
||||
*/ |
||||
private String credit; |
||||
|
||||
/** |
||||
* 学时 |
||||
*/ |
||||
private String courseHours; |
||||
|
||||
/** |
||||
* 绩点 |
||||
*/ |
||||
private String gradePoint; |
||||
|
||||
/** |
||||
* 考核方式 |
||||
*/ |
||||
private String evaluateMethod; |
||||
|
||||
/** |
||||
* 考试性质 |
||||
*/ |
||||
private String kind; |
||||
|
||||
/** |
||||
* 课程性质 |
||||
*/ |
||||
private String courseKind; |
||||
} |
@ -0,0 +1,41 @@ |
||||
package cn.linghang.mywust.network.entitys; |
||||
|
||||
import cn.linghang.mywust.util.StringUtil; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.TreeMap; |
||||
|
||||
public class FormBodyBuilder { |
||||
private final Map<String, String> queryParams; |
||||
|
||||
public FormBodyBuilder(Map<String, String> queryParams) { |
||||
this.queryParams = queryParams; |
||||
} |
||||
|
||||
public FormBodyBuilder() { |
||||
this.queryParams = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); |
||||
} |
||||
|
||||
public FormBodyBuilder(int initSize) { |
||||
this.queryParams = new HashMap<>(initSize); |
||||
} |
||||
|
||||
public FormBodyBuilder addQueryParams(Map<String, String> params) { |
||||
this.queryParams.putAll(params); |
||||
return this; |
||||
} |
||||
|
||||
public FormBodyBuilder addQueryParam(String key, String value) { |
||||
this.queryParams.put(key, value); |
||||
return this; |
||||
} |
||||
|
||||
public Map<String, String> build() { |
||||
return this.queryParams; |
||||
} |
||||
|
||||
public String buildAndToString() { |
||||
return StringUtil.generateQueryString(this.queryParams); |
||||
} |
||||
} |
@ -1,4 +1,4 @@ |
||||
package cn.linghang.mywust.network; |
||||
package cn.linghang.mywust.network.entitys; |
||||
|
||||
import lombok.Data; |
||||
|
@ -1,4 +1,4 @@ |
||||
package cn.linghang.mywust.network; |
||||
package cn.linghang.mywust.network.entitys; |
||||
|
||||
import lombok.Data; |
||||
|
@ -0,0 +1,45 @@ |
||||
import cn.linghang.mywust.core.exception.BasicException; |
||||
import cn.linghang.mywust.core.service.undergraduate.ExamInfoApi; |
||||
import cn.linghang.mywust.model.undergrade.ExamInfo; |
||||
import cn.linghang.mywust.network.RequestClientOption; |
||||
import cn.linghang.mywust.network.Requester; |
||||
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
import java.util.Scanner; |
||||
|
||||
public class ExamInfoTest { |
||||
public static void main(String[] args) throws BasicException, IOException { |
||||
new ExamInfoTest().run(); |
||||
} |
||||
|
||||
private void run() throws BasicException, IOException { |
||||
System.out.println("成绩获取"); |
||||
System.out.println("Cookie:"); |
||||
|
||||
Scanner scanner = new Scanner(System.in); |
||||
|
||||
String cookie = scanner.nextLine(); |
||||
|
||||
System.out.println("使用Cookie:" + cookie); |
||||
|
||||
Requester requester = new SimpleOkhttpRequester(); |
||||
ExamInfoApi jwcService = new ExamInfoApi(requester); |
||||
|
||||
RequestClientOption option = new RequestClientOption(); |
||||
option.setTimeout(5); |
||||
RequestClientOption.Proxy proxy = new RequestClientOption.Proxy(); |
||||
proxy.setPort(6060); |
||||
proxy.setAddress("127.0.0.1"); |
||||
option.setProxy(proxy); |
||||
option.setFallowUrlRedirect(false); |
||||
|
||||
List<ExamInfo> infos = jwcService.getExamInfo(cookie, option); |
||||
|
||||
for (ExamInfo info : infos) { |
||||
|
||||
System.out.println(info); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
import cn.linghang.mywust.core.exception.BasicException; |
||||
import cn.linghang.mywust.core.service.undergraduate.ExamInfoApi; |
||||
import cn.linghang.mywust.core.service.undergraduate.SchemeApi; |
||||
import cn.linghang.mywust.model.undergrade.ExamInfo; |
||||
import cn.linghang.mywust.network.RequestClientOption; |
||||
import cn.linghang.mywust.network.Requester; |
||||
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
import java.util.Scanner; |
||||
|
||||
public class SchemeTest { |
||||
public static void main(String[] args) throws BasicException, IOException { |
||||
new SchemeTest().run(); |
||||
} |
||||
|
||||
private void run() throws BasicException, IOException { |
||||
System.out.println("培养方案获取"); |
||||
System.out.println("Cookie:"); |
||||
|
||||
Scanner scanner = new Scanner(System.in); |
||||
|
||||
String cookie = scanner.nextLine(); |
||||
|
||||
System.out.println("使用Cookie:" + cookie); |
||||
|
||||
RequestClientOption option = new RequestClientOption(); |
||||
option.setTimeout(5); |
||||
RequestClientOption.Proxy proxy = new RequestClientOption.Proxy(); |
||||
proxy.setPort(6060); |
||||
proxy.setAddress("127.0.0.1"); |
||||
option.setProxy(proxy); |
||||
option.setFallowUrlRedirect(false); |
||||
|
||||
Requester requester = new SimpleOkhttpRequester(); |
||||
SchemeApi jwcService = new SchemeApi(requester); |
||||
|
||||
String page = jwcService.getPrueSchemePage(cookie, option); |
||||
|
||||
System.out.println(page); |
||||
} |
||||
} |
@ -0,0 +1,41 @@ |
||||
import cn.linghang.mywust.core.exception.BasicException; |
||||
import cn.linghang.mywust.core.parser.undergraduate.StudentInfoPageParser; |
||||
import cn.linghang.mywust.core.service.auth.JwcLogin; |
||||
import cn.linghang.mywust.core.service.auth.UnionLogin; |
||||
import cn.linghang.mywust.core.service.undergraduate.StudentInfoApi; |
||||
import cn.linghang.mywust.model.undergrade.StudentInfo; |
||||
import cn.linghang.mywust.network.RequestClientOption; |
||||
import cn.linghang.mywust.network.Requester; |
||||
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Scanner; |
||||
|
||||
public class StudentInfoPageTest { |
||||
public static void main(String[] args) throws BasicException, IOException { |
||||
new StudentInfoPageTest().run(); |
||||
} |
||||
|
||||
private void run() throws BasicException, IOException { |
||||
System.out.println("学生信息获取"); |
||||
System.out.println("Cookie:"); |
||||
|
||||
Scanner scanner = new Scanner(System.in); |
||||
|
||||
String cookie = scanner.nextLine(); |
||||
|
||||
System.out.println("使用Cookie:" + cookie); |
||||
|
||||
Requester requester = new SimpleOkhttpRequester(); |
||||
StudentInfoApi jwcService = new StudentInfoApi(requester); |
||||
|
||||
RequestClientOption option = new RequestClientOption(); |
||||
option.setTimeout(5); |
||||
option.setProxy(null); |
||||
option.setFallowUrlRedirect(false); |
||||
|
||||
StudentInfo info = jwcService.getStudentInfo(cookie, option); |
||||
|
||||
System.out.println(info); |
||||
} |
||||
} |
Loading…
Reference in new issue