diff --git a/mywust-core/pom.xml b/mywust-core/pom.xml
index 0b4c3c3..bae1a93 100644
--- a/mywust-core/pom.xml
+++ b/mywust-core/pom.xml
@@ -54,6 +54,12 @@
2.14.0-rc1
compile
+
+
+ cn.hutool
+ hutool-core
+ ${hutool.version}
+
@@ -63,5 +69,6 @@
2.0.3
1.15.3
+ 5.8.12
\ No newline at end of file
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/api/PhysicsSystemUrls.java b/mywust-core/src/main/java/cn/linghang/mywust/core/api/PhysicsSystemUrls.java
index 4be73c3..8041fb5 100644
--- a/mywust-core/src/main/java/cn/linghang/mywust/core/api/PhysicsSystemUrls.java
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/api/PhysicsSystemUrls.java
@@ -9,6 +9,10 @@ public class PhysicsSystemUrls {
public static final String PHYSICS_SYSTEM_INDEX_URL = "http://wlsy.wust.edu.cn:7101/Page/PEE/PEECM/PEECM0001.aspx";
+ public static final String PHYSICS_SCORE_LIST_URL = "http://wlsy.wust.edu.cn:7101/Page/PEE/PEECM/PEECM0001.aspx?flag=2&&action=PEE63&&moduleId=PEE63";
+
+ public static final String PHYSICS_SCORE_URL = "http://wlsy.wust.edu.cn:7101/Page/PEE/PEECM/PEECM0001.aspx?flag=2&&&action=PEE63&moduleId=PEE63";
+
public static final String PHYSICS_COURSE_INDEX_URL = "http://wlsy.wust.edu.cn:7101/Page/PEE/PEECM/PEECM0001.aspx?flag=1&&action=PEE110101&&moduleId=PEE11";
public static final String PHYSICS_COURSE_API = "http://wlsy.wust.edu.cn:7101/Page/PEE/PEECM/PEECM0001.aspx?action=PEE110301&&parentId=PEE11";
}
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/PhysicsScoreListPageParser.java b/mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/PhysicsScoreListPageParser.java
new file mode 100644
index 0000000..304f5b3
--- /dev/null
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/PhysicsScoreListPageParser.java
@@ -0,0 +1,39 @@
+package cn.linghang.mywust.core.parser.physics;
+
+import cn.linghang.mywust.core.exception.ParseException;
+import cn.linghang.mywust.core.parser.Parser;
+import cn.linghang.mywust.core.util.JsoupUtil;
+import lombok.Data;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PhysicsScoreListPageParser implements Parser {
+ private static final String scorePageLinkXpath = "//*[@id=\"ID_PEE63_gvpeeCourseScore\"]/tbody/tr/td/a";
+
+ @Override
+ public PhysicsScoreListPageParseResult parse(String html) throws ParseException {
+ List scoreIds = new ArrayList<>(2);
+ Document document = Jsoup.parse(html);
+ Elements links = document.selectXpath(scorePageLinkXpath);
+ for (Element link : links) {
+ String href = link.attr("href");
+ scoreIds.add(href.replaceAll("javascript:__doPostBack\\('(.*?)',''\\)", "$1"));
+ }
+
+ Element termSelect = document.getElementById("ID_PEE63_ddlxq");
+ String term = JsoupUtil.getSelectValue(termSelect);
+
+ return new PhysicsScoreListPageParseResult(scoreIds, term);
+ }
+
+ @Data
+ public static class PhysicsScoreListPageParseResult {
+ private final List courseIds;
+ private final String term;
+ }
+}
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/PhysicsScorePageParser.java b/mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/PhysicsScorePageParser.java
new file mode 100644
index 0000000..d41ac50
--- /dev/null
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/PhysicsScorePageParser.java
@@ -0,0 +1,42 @@
+package cn.linghang.mywust.core.parser.physics;
+
+import cn.linghang.mywust.core.exception.ParseException;
+import cn.linghang.mywust.core.parser.Parser;
+import cn.linghang.mywust.core.util.JsoupUtil;
+import cn.linghang.mywust.data.global.Score;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PhysicsScorePageParser implements Parser> {
+ private static final String scoreRowXpath = "//*[@id=\"ID_PEE63_gvpeeLabScore\"]/tbody/tr[@style=\"background-color:White;height:25px;\"]";
+
+ @Override
+ public List parse(String html) throws ParseException {
+ Elements scoreRows = Jsoup.parse(html).selectXpath(scoreRowXpath);
+
+ List scores = new ArrayList<>(scoreRows.size());
+ for (Element scoreRow : scoreRows) {
+ Elements girds = scoreRow.getElementsByTag("td");
+ // 某行格子数少于8个,即到了成绩那部分就没了,就跳过
+ if (girds.size() < 8) {
+ continue;
+ }
+
+ // 有用的信息就这么多
+ Score score = new Score();
+ score.setId(JsoupUtil.getElementText(girds, 0));
+ score.setCourseName(JsoupUtil.getElementText(girds, 1));
+ score.setGroupName(JsoupUtil.getElementText(girds, 2));
+ score.setFlag(JsoupUtil.getElementText(girds, 6));
+ score.setScore(JsoupUtil.getElementText(girds, 7));
+
+ scores.add(score);
+ }
+
+ return scores;
+ }
+}
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/UndergradCourseTableParser.java b/mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/UndergradCourseTableParser.java
index af87383..767d384 100644
--- a/mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/UndergradCourseTableParser.java
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/UndergradCourseTableParser.java
@@ -86,7 +86,7 @@ public class UndergradCourseTableParser implements Parser> {
courseBuilder.endSection(lineIndex * 2 + 2);
// 不直接使用String.split而是手动分割,是因为系统自带split方法每次调用都需要编译一次切割正则,效率不太行
- String timeText = timeElements.isEmpty() ? "" : StringUtil.split(timeElements.get(0).text(), ',').get(0);
+ String timeText = timeElements.isEmpty() ? "" : StringUtil.split(JsoupUtil.getElementText(timeElements, 0), ',').get(0);
List times = StringUtil.split(timeText, ',');
for (String time : times) {
Matcher weekMatcher = WEEK_REGEX.matcher(time);
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/request/physics/PhysicsSystemRequestFactory.java b/mywust-core/src/main/java/cn/linghang/mywust/core/request/physics/PhysicsSystemRequestFactory.java
index 8e1b31e..2f6aecd 100644
--- a/mywust-core/src/main/java/cn/linghang/mywust/core/request/physics/PhysicsSystemRequestFactory.java
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/request/physics/PhysicsSystemRequestFactory.java
@@ -2,6 +2,7 @@ package cn.linghang.mywust.core.request.physics;
import cn.linghang.mywust.core.api.PhysicsSystemUrls;
import cn.linghang.mywust.core.request.RequestFactory;
+import cn.linghang.mywust.core.util.PageFormExtractor;
import cn.linghang.mywust.network.entitys.HttpRequest;
import cn.linghang.mywust.util.StringUtil;
@@ -14,9 +15,13 @@ public class PhysicsSystemRequestFactory extends RequestFactory {
return makeHttpRequest(PhysicsSystemUrls.PHYSICS_LOGIN_INDEX);
}
- public static HttpRequest loginCookiesRequest(String username, String password, String cookies) {
- byte[] queryData = StringUtil.generateQueryString(makeLoginQueryParam(username, password)).getBytes(StandardCharsets.UTF_8);
- return makeHttpRequest(PhysicsSystemUrls.PHYSICS_LOGIN_COOKIES_API, queryData, cookies);
+ public static HttpRequest loginCookiesRequest(String username, String password, String loginIndexHtml) {
+ Map params = PageFormExtractor.extractAllParams(loginIndexHtml);
+ String viewState = params.get("__VIEWSTATE");
+
+ String queryData = StringUtil.generateQueryString(makeLoginQueryParam(username, password, viewState));
+
+ return makeHttpRequest(PhysicsSystemUrls.PHYSICS_LOGIN_COOKIES_API, queryData);
}
public static HttpRequest mainIndexRequest(String cookies) {
@@ -27,33 +32,52 @@ public class PhysicsSystemRequestFactory extends RequestFactory {
return makeHttpRequest(redirect, null, cookies);
}
- public static HttpRequest physicsCourseIndexRequest(Map indexParam, String cookies) {
- // 补上“动态”生成的参数
- indexParam.put("smLabManage", "upnMenu|lnk_2");
- indexParam.put("__EVENTTARGET", "lnk_2");
- indexParam.put("ID_PEE01$NoticeType", "-999");
- indexParam.put("ID_PEE01$txtCreater", "");
- indexParam.put("ID_PEE01$IsRead", "-999");
- indexParam.put("ID_PEE01$ObjPager_input", "1");
- indexParam.put("__ASYNCPOST", "true");
-
- byte[] fromData = StringUtil.generateQueryString(indexParam).getBytes(StandardCharsets.UTF_8);
- return makeHttpRequest(PhysicsSystemUrls.PHYSICS_COURSE_INDEX_URL, fromData, cookies);
- }
-
public static HttpRequest physicsCourseRequest(String cookies) {
return makeHttpRequest(PhysicsSystemUrls.PHYSICS_COURSE_API, null, cookies);
}
- private static Map makeLoginQueryParam(String username, String password) {
- // 这几个算是是写死了的,也能用
- // 但其实最好还是从首页动态获取某些关键字段("__VIEWSTATE")
- // 这种办法等后面有时间了再实现
+ public static HttpRequest physicsScoreListRequest(String cookies) {
+ return makeHttpRequest(PhysicsSystemUrls.PHYSICS_SCORE_LIST_URL, null, cookies);
+ }
+
+ public static HttpRequest physicsScoreRequest(String cookies, String courseId, Map params) {
+ String data = StringUtil.generateQueryString(makeScoreQueryParam(courseId, params));
+ return makeStringDataHttpRequest(PhysicsSystemUrls.PHYSICS_SCORE_URL, data, cookies);
+ }
+
+ private static Map makeScoreQueryParam(String courseId, Map params) {
+ Map queryParams = new HashMap<>(17);
+
+ String viewState = params.get("__VIEWSTATE");
+ String student = params.get("ID_PEE63$hidStudentID");
+ // 可能是写死的,但不好说
+ String server = params.get("ID_PEE63$hidPG");
+ String term = params.get("ID_PEE63$ddlxq");
+
+ queryParams.put("smLabManage", "ID_PEE63$upn140201|" + courseId);
+ queryParams.put("__EVENTTARGET", courseId);
+ queryParams.put("__EVENTARGUMENT", "");
+ queryParams.put("__LASTFOCUS", "");
+ queryParams.put("__VIEWSTATE", viewState);
+ queryParams.put("__VIEWSTATEGENERATOR", "4B5F03FE");
+ queryParams.put("hidRoleType", "");
+ queryParams.put("ID_PEE63$hidStudentID", student);
+ queryParams.put("ID_PEE63$hidCourseID", "");
+ queryParams.put("ID_PEE63$hidColumnNum", "");
+ queryParams.put("ID_PEE63$hidPG", server);
+ // 这个需要手动补充
+ queryParams.put("ID_PEE63$ddlxq", term);
+ queryParams.put("__ASYNCPOST", "true");
+
+ return queryParams;
+ }
+
+ private static Map makeLoginQueryParam(String username, String password, String viewState) {
Map queryParams = new HashMap<>(12);
queryParams.put("__EVENTTARGET", "");
queryParams.put("__EVENTARGUMENT", "");
- queryParams.put("__VIEWSTATE", VIEW_STATE);
+ queryParams.put("__VIEWSTATE", viewState);
queryParams.put("__VIEWSTATEGENERATOR", "F42971E6");
queryParams.put("hidUserID", "");
queryParams.put("hidUserPassWord", "");
@@ -66,18 +90,4 @@ public class PhysicsSystemRequestFactory extends RequestFactory {
return queryParams;
}
-
- private static final String VIEW_STATE =
- "/wEPDwULLTEwNTgzMzY4NTgPZBYCZg9kFgICCQ9kFgJmD2QWBgINDw9kFgIeBVN0" +
- "eWxlBZsBbGluZS1oZWlnaHQ6NThweDtwYWRkaW5nLWxlZnQ6NDVweDtwYWRkaW5n" +
- "LXRvcDowcHg7d2lkdGg6MzE1cHg7aGVpZ2h0OjU0cHg7YmFja2dyb3VuZDp1cmwo" +
- "Li4vLi4vUmVzb3VyY2UvQmFzaWNJbmZvL25ld0JHL+eUqOaIt+WQjS5wbmcpIG5v" +
- "LXJlcGVhdCAwcHggMHB4OztkAg8PD2QWAh8ABZsBbGluZS1oZWlnaHQ6NThweDtw" +
- "YWRkaW5nLWxlZnQ6NDVweDtwYWRkaW5nLXRvcDowcHg7d2lkdGg6MzE1cHg7aGVp" +
- "Z2h0OjU0cHg7YmFja2dyb3VuZDp1cmwoLi4vLi4vUmVzb3VyY2UvQmFzaWNJbmZv" +
- "L25ld0JHL+Wvhueggeepui5wbmcpIG5vLXJlcGVhdCAwcHggMHB4OztkAhkPDxYC" +
- "HgRUZXh0BRvns7vnu5/orr/pl67kurrmrKHvvJozNjc2MDJkZBgBBR5fX0NvbnRy" +
- "b2xzUmVxdWlyZVBvc3RCYWNrS2V5X18WBQULaW1nQnRuQ2xvc2UFCGxidGJTYXZl" +
- "BQpsYnRuQ2FuY2VsBQhidG5Mb2dpbgUKY2JTYXZlSW5mb6K8UayJuWe2OSRVqLDo" +
- "2J4wMKAT";
}
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/request/undergrade/BkjxRequestFactory.java b/mywust-core/src/main/java/cn/linghang/mywust/core/request/undergrade/BkjxRequestFactory.java
index 7cb3c3d..fc7ddaf 100644
--- a/mywust-core/src/main/java/cn/linghang/mywust/core/request/undergrade/BkjxRequestFactory.java
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/request/undergrade/BkjxRequestFactory.java
@@ -108,7 +108,7 @@ public class BkjxRequestFactory extends RequestFactory {
return makeHttpRequest(UndergradUrls.Legacy.BKJX_DATA_STRING_API);
}
- public static HttpRequest ticketRedirectRequest(String encode) {
+ public static HttpRequest ticketRedirectRequest(String encode, String cookies) {
Map queryParams = new HashMap<>(4);
queryParams.put("userAccount", "");
queryParams.put("userPassword", "");
@@ -120,7 +120,7 @@ public class BkjxRequestFactory extends RequestFactory {
extendHeaders.put("Referer", "http://bkjx.wust.edu.cn/");
extendHeaders.put("Origin", "http://bkjx.wust.edu.cn");
- return makeHttpRequest(UndergradUrls.Legacy.BKJX_SESSION_COOKIE_API, queryString.getBytes(StandardCharsets.UTF_8))
+ return makeHttpRequest(UndergradUrls.Legacy.BKJX_SESSION_COOKIE_API, queryString.getBytes(StandardCharsets.UTF_8), cookies)
.addHeaders(extendHeaders);
}
}
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/PhysicsLogin.java b/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/PhysicsLogin.java
index 4360cf6..2af12fe 100644
--- a/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/PhysicsLogin.java
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/PhysicsLogin.java
@@ -26,8 +26,13 @@ public class PhysicsLogin {
}
public String getLoginCookie(String username, String password, RequestClientOption requestClientOption) throws IOException, ApiException, ParseException {
+ // 获取“动态”的表单参数,例如__VIEWSTATE等
+ HttpRequest loginIndexPageRequest = PhysicsSystemRequestFactory.loginIndexRequest();
+ HttpResponse loginIndexPageResponse = requester.get(loginIndexPageRequest);
+ String loginIndex = loginIndexPageResponse.getStringBody();
+
// 直接登录,ASP.NET_SessionId其实在这步就能获取到,不需要再请求一遍首页获取
- HttpRequest loginCookieRequest = PhysicsSystemRequestFactory.loginCookiesRequest(username, password, null);
+ HttpRequest loginCookieRequest = PhysicsSystemRequestFactory.loginCookiesRequest(username, password, loginIndex);
HttpResponse loginCookieResponse = requester.post(loginCookieRequest, requestClientOption);
if (loginCookieResponse.getStatusCode() != HttpResponse.HTTP_REDIRECT_302) {
throw new ApiException(ApiException.Code.PHYSICS_PASSWORD_WRONG);
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/UndergraduateLogin.java b/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/UndergraduateLogin.java
index 5fd23d3..295eaa2 100644
--- a/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/UndergraduateLogin.java
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/UndergraduateLogin.java
@@ -35,16 +35,7 @@ public class UndergraduateLogin {
HttpResponse sessionResponse = requester.get(sessionRequest, requestOption);
String cookies = sessionResponse.getCookies();
- if (roughCheckCookieFail(cookies)) {
- log.error("[mywust]: Cookie粗查不通过:{}", cookies);
- throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION, "登录获取的Cookie无效");
- }
-
- // 检查Cookie是否真正可用,同时请求一次任意接口使后续接口能够正确响应
- // 拿到Cookie后调用的第一个接口会产生302/301跳转,需要再次调用才能正确响应
- if (checkCookiesFail(cookies, requestOption)) {
- log.warn("[mywust]: Cookie检查不通过:{}", cookies);
- }
+ this.checkCookie(cookies, requestOption);
return cookies;
}
@@ -56,26 +47,24 @@ public class UndergraduateLogin {
*
* @return 获取到的Cookies
*/
- @Deprecated
public String getLoginCookieLegacy(String username, String password, RequestClientOption requestOption) throws IOException, ApiException {
// 获取某段神秘的dataStr(反正官网代码是这么叫的)
HttpRequest dataStringRequest = BkjxRequestFactory.Legacy.dataStringRequest();
HttpResponse dataStringResponse = requester.post(dataStringRequest, requestOption);
if (dataStringResponse.getBody() == null) {
- log.warn("[mywust]: 本科教学系统旧版登录方式:获取dataStr时发生错误");
+ log.warn("[mywust]: 本科教学系统旧版登录:获取dataStr时发生错误");
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION);
}
- String dataString = new String(dataStringResponse.getBody());
+ String dataString = dataStringResponse.getStringBody();
// 获取登录ticket
String encoded = PasswordEncoder.legacyPassword(username, password, dataString);
- HttpRequest ticketRequest = BkjxRequestFactory.Legacy.ticketRedirectRequest(encoded);
- ticketRequest.setCookies(dataStringResponse.getCookies());
-
+ HttpRequest ticketRequest = BkjxRequestFactory.Legacy.ticketRedirectRequest(encoded, dataStringResponse.getCookies());
HttpResponse ticketResponse = requester.post(ticketRequest, requestOption);
+
if (ticketResponse.getBody() == null) {
- log.warn("[mywust]: 本科教学系统旧版登录方式:获取登录ticket时发生错误");
+ log.warn("[mywust]: 本科教学系统旧版登录:获取登录ticket时发生错误");
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION);
}
@@ -89,18 +78,22 @@ public class UndergraduateLogin {
HttpResponse sessionResponse = requester.get(sessionRequest, requestOption);
String cookies = sessionResponse.getCookies();
+ this.checkCookie(cookies, requestOption);
+
+ return cookies;
+ }
+
+ private void checkCookie(String cookies, RequestClientOption requestOption) throws ApiException, IOException {
if (roughCheckCookieFail(cookies)) {
log.error("[mywust]: Cookie粗查不通过:{}", cookies);
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION, "登录获取的Cookie无效");
}
// 检查Cookie是否真正可用,同时请求一次任意接口使后续接口能够正确响应
- // 拿到Cookie后调用的第一个接口会产生302/301跳转,需要再次调用才能正确响应
+ // 拿到Cookie后调用的第一个接口有时候会产生302/301跳转到主页,需要再次调用才能正确响应
if (checkCookiesFail(cookies, requestOption)) {
log.warn("[mywust]: Cookie检查不通过:{}", cookies);
}
-
- return cookies;
}
private boolean roughCheckCookieFail(String cookies) {
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsApiServiceBase.java b/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsApiServiceBase.java
new file mode 100644
index 0000000..fb104dd
--- /dev/null
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsApiServiceBase.java
@@ -0,0 +1,19 @@
+package cn.linghang.mywust.core.service.physics;
+
+import cn.linghang.mywust.core.exception.ApiException;
+import cn.linghang.mywust.network.Requester;
+import cn.linghang.mywust.network.entitys.HttpResponse;
+
+public abstract class PhysicsApiServiceBase {
+ protected final Requester requester;
+
+ public PhysicsApiServiceBase(Requester requester) {
+ this.requester = requester;
+ }
+
+ protected void checkResponse(HttpResponse response) throws ApiException {
+ if (response.getStatusCode() != HttpResponse.HTTP_OK) {
+ throw new ApiException(ApiException.Code.COOKIE_INVALID);
+ }
+ }
+}
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsApiService.java b/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsCourseApiServiceBase.java
similarity index 61%
rename from mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsApiService.java
rename to mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsCourseApiServiceBase.java
index d99ca4e..599a5ca 100644
--- a/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsApiService.java
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsCourseApiServiceBase.java
@@ -9,22 +9,18 @@ import cn.linghang.mywust.network.entitys.HttpResponse;
import java.io.IOException;
-public class PhysicsApiService {
- private final Requester requester;
-
- public PhysicsApiService(Requester requester) {
- this.requester = requester;
+public class PhysicsCourseApiServiceBase extends PhysicsApiServiceBase {
+ public PhysicsCourseApiServiceBase(Requester requester) {
+ super(requester);
}
- public String getCoursePage(String cookie, RequestClientOption requestClientOption) throws IOException, ApiException {
+ public String getPage(String cookie, RequestClientOption requestClientOption) throws IOException, ApiException {
requestClientOption.setFallowUrlRedirect(false);
- // 请求真正的课表页
+ // 直接请求真正的课表页
HttpRequest coursePageRequest = PhysicsSystemRequestFactory.physicsCourseRequest(cookie);
HttpResponse courseResponse = requester.get(coursePageRequest, requestClientOption);
- if (courseResponse.getStatusCode() != HttpResponse.HTTP_OK) {
- throw new ApiException(ApiException.Code.COOKIE_INVALID);
- }
+ checkResponse(courseResponse);
return new String(courseResponse.getBody());
}
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsScoreApiServiceBase.java b/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsScoreApiServiceBase.java
new file mode 100644
index 0000000..70abbfe
--- /dev/null
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsScoreApiServiceBase.java
@@ -0,0 +1,52 @@
+package cn.linghang.mywust.core.service.physics;
+
+import cn.linghang.mywust.core.exception.ApiException;
+import cn.linghang.mywust.core.exception.ParseException;
+import cn.linghang.mywust.core.parser.physics.PhysicsScoreListPageParser;
+import cn.linghang.mywust.core.request.physics.PhysicsSystemRequestFactory;
+import cn.linghang.mywust.core.util.PageFormExtractor;
+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;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class PhysicsScoreApiServiceBase extends PhysicsApiServiceBase {
+
+ private static final PhysicsScoreListPageParser scoreListPageParser = new PhysicsScoreListPageParser();
+
+ public PhysicsScoreApiServiceBase(Requester requester) {
+ super(requester);
+ }
+
+ public String getPage(String cookie, String courseId, Map pageParams, RequestClientOption requestClientOption) throws IOException, ApiException, ParseException {
+ HttpRequest scorePageRequest = PhysicsSystemRequestFactory.physicsScoreRequest(cookie, courseId, pageParams);
+ HttpResponse scorePageResponse = requester.post(scorePageRequest, requestClientOption);
+ checkResponse(scorePageResponse);
+
+ return scorePageResponse.getStringBody();
+ }
+
+ public List getAllPages(String cookie, RequestClientOption requestClientOption) throws IOException, ParseException, ApiException {
+ HttpRequest scoreListPageRequest = PhysicsSystemRequestFactory.physicsScoreListRequest(cookie);
+ HttpResponse scoreListPageResponse = requester.get(scoreListPageRequest, requestClientOption);
+ String scoreListPage = scoreListPageResponse.getStringBody();
+
+ PhysicsScoreListPageParser.PhysicsScoreListPageParseResult pageParseResult = scoreListPageParser.parse(scoreListPage);
+
+ Map pageParams = PageFormExtractor.extractAllParams(scoreListPage);
+ pageParams.put("ID_PEE63$ddlxq", pageParseResult.getTerm());
+
+ List courseIds = pageParseResult.getCourseIds();
+ List scorePages = new ArrayList<>(courseIds.size());
+ for (String courseId : courseIds) {
+ scorePages.add(this.getPage(cookie, courseId, pageParams, requestClientOption));
+ }
+
+ return scorePages;
+ }
+}
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/util/JsoupUtil.java b/mywust-core/src/main/java/cn/linghang/mywust/core/util/JsoupUtil.java
index cbcd0e3..bc386bb 100644
--- a/mywust-core/src/main/java/cn/linghang/mywust/core/util/JsoupUtil.java
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/util/JsoupUtil.java
@@ -92,6 +92,21 @@ public class JsoupUtil {
}
}
+ /**
+ * 从select类型的Element中拿取到已选中的选项值value字段
+ *
+ * @param element 元素对象
+ * @return 相应的值,若element为空则返回空字符串
+ */
+ public static String getSelectValue(Element element) {
+ if (element == null) {
+ return "";
+ } else {
+ return element.getElementsByAttributeValue("selected", "selected")
+ .attr("value");
+ }
+ }
+
/**
* 取元素集合中第一个元素的文本,当elements为null或数量为0时,返回空字符串
*
diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/util/PageFormExtractor.java b/mywust-core/src/main/java/cn/linghang/mywust/core/util/PageFormExtractor.java
index 8bbb048..fcea906 100644
--- a/mywust-core/src/main/java/cn/linghang/mywust/core/util/PageFormExtractor.java
+++ b/mywust-core/src/main/java/cn/linghang/mywust/core/util/PageFormExtractor.java
@@ -5,7 +5,10 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
+import java.util.HashMap;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* html页面表单参数提取,用于简化部分繁琐的表单数据生成,模拟网页表单数据的请求参数
@@ -24,4 +27,16 @@ public class PageFormExtractor {
targetMap.put(element.attr("name"), element.attr("value"));
}
}
+
+ private static final Pattern formPattern = Pattern.compile("name=\"(?.*?)\"(.*?)value=\"(?.*?)\"");
+
+ public static Map extractAllParams(String wholeHtml) {
+ Map params = new HashMap<>(16);
+ Matcher matcher = formPattern.matcher(wholeHtml);
+ while (matcher.find()) {
+ params.put(matcher.group("name"), matcher.group("value"));
+ }
+
+ return params;
+ }
}
diff --git a/mywust-test/pom.xml b/mywust-test/pom.xml
index 35887c8..63a376f 100644
--- a/mywust-test/pom.xml
+++ b/mywust-test/pom.xml
@@ -61,6 +61,12 @@
RELEASE
test
+
+ cn.linghang
+ mywust-core
+ 0.0.2-SNAPSHOT
+ compile
+
diff --git a/mywust-util/pom.xml b/mywust-util/pom.xml
index 42ae0fc..b146440 100644
--- a/mywust-util/pom.xml
+++ b/mywust-util/pom.xml
@@ -15,6 +15,8 @@
1.8
8
UTF-8
+
+ 5.8.12
@@ -30,5 +32,11 @@
guava
31.1-jre
+
+
+ cn.hutool
+ hutool-core
+ ${hutool.version}
+
\ No newline at end of file
diff --git a/mywust-util/src/main/java/cn/linghang/mywust/util/StringUtil.java b/mywust-util/src/main/java/cn/linghang/mywust/util/StringUtil.java
index 0a96a1c..59bc893 100644
--- a/mywust-util/src/main/java/cn/linghang/mywust/util/StringUtil.java
+++ b/mywust-util/src/main/java/cn/linghang/mywust/util/StringUtil.java
@@ -1,10 +1,10 @@
package cn.linghang.mywust.util;
+import cn.hutool.core.util.URLUtil;
import com.google.common.base.Joiner;
import org.apache.commons.codec.binary.Base64;
import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
@@ -20,12 +20,7 @@ public class StringUtil {
public static String generateQueryString(Map queryParams) {
// 自动对value值进行url编码
Map urlEncodedQueryParams = new TreeMap<>(REPEATABLE_COMPARATOR);
- queryParams.forEach((k, v) -> {
- try {
- urlEncodedQueryParams.put(k, URLEncoder.encode(v, StandardCharsets.UTF_8.name()));
- } catch (UnsupportedEncodingException ignored) {
- }
- });
+ queryParams.forEach((k, v) -> urlEncodedQueryParams.put(URLUtil.encodeAll(k), URLUtil.encodeAll(v)));
return Joiner.on('&')
.useForNull("")