Compare commits
9 Commits
036c4b47be
...
0c47043757
Author | SHA1 | Date |
---|---|---|
lensfrex | 0c47043757 | 2 years ago |
lensfrex | ebf06af1a7 | 2 years ago |
lensfrex | 5c94e98269 | 2 years ago |
lensfrex | 4743d9ace0 | 2 years ago |
lensfrex | 12648a7ad0 | 2 years ago |
lensfrex | 950e3ca948 | 2 years ago |
lensfrex | 24c23c33e1 | 2 years ago |
lensfrex | 79c6659509 | 2 years ago |
lensfrex | d6fc6f9878 | 2 years ago |
@ -0,0 +1,17 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<packaging>pom</packaging> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>1.18.22</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,58 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-core</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-network</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-util</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-api</artifactId> |
||||
<version>2.0.3</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.jsoup</groupId> |
||||
<artifactId>jsoup</artifactId> |
||||
<version>1.15.3</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-model</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.fasterxml.jackson.core</groupId> |
||||
<artifactId>jackson-annotations</artifactId> |
||||
<version>2.14.0-rc1</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.fasterxml.jackson.core</groupId> |
||||
<artifactId>jackson-databind</artifactId> |
||||
<version>2.14.0-rc1</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>1.18.22</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -1,5 +0,0 @@ |
||||
package cn.linghang.mywust.core; |
||||
|
||||
public class Mywust { |
||||
|
||||
} |
@ -1,5 +0,0 @@ |
||||
package cn.linghang.mywust.core; |
||||
|
||||
public class MywustFactory { |
||||
|
||||
} |
@ -1,6 +1,6 @@ |
||||
package cn.linghang.mywust.core.api; |
||||
|
||||
public class Graduate { |
||||
public class GraduateUrls { |
||||
public static final String GRADUATE_CAPTCHA_API = "http://59.68.177.189/pyxx/PageTemplate/NsoftPage/yzm/createyzm.aspx"; |
||||
public static final String GRADUATE_LOGIN_API = "http://59.68.177.189/pyxx/login.aspx"; |
||||
|
@ -1,6 +1,6 @@ |
||||
package cn.linghang.mywust.core.api; |
||||
|
||||
public class Library { |
||||
public class LibraryUrls { |
||||
public static final String LIBRARY_SESSION_COOKIE_API = "https://libsys.wust.edu.cn/meta-local/opac/cas/rosetta?ticket=%s"; |
||||
|
||||
public static final String LIBRARY_INDEX_URL = "https://libsys.wust.edu.cn/meta-local/opac/cas/rosetta"; |
@ -1,6 +1,6 @@ |
||||
package cn.linghang.mywust.core.api; |
||||
|
||||
public class PhysicsSystem { |
||||
public class PhysicsSystemUrls { |
||||
public static final String PHYSICS_LOGIN_INDEX = "http://wlsy.wust.edu.cn/Page/BI/BI000.aspx"; |
||||
|
||||
public static final String PHYSICS_LOGIN_COOKIES_API = "http://wlsy.wust.edu.cn/Page/BI/BI000.aspx"; |
@ -1,6 +1,6 @@ |
||||
package cn.linghang.mywust.core.api; |
||||
|
||||
public class UnionAuth { |
||||
public class UnionAuthUrls { |
||||
/** |
||||
* 统一认证登录验证的api地址,请求之后可进一步获取service ticket来对具体的服务进行登录获取Cookies |
||||
*/ |
@ -1,72 +0,0 @@ |
||||
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.util.JsoupUtil; |
||||
import cn.linghang.mywust.model.global.ExamInfo; |
||||
import org.jsoup.Jsoup; |
||||
import org.jsoup.nodes.Element; |
||||
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(html); |
||||
} |
||||
|
||||
List<ExamInfo> examInfos = new ArrayList<>(rows.size()); |
||||
|
||||
try { |
||||
for (Element row : rows) { |
||||
// 提取出当前行的所有格子
|
||||
Elements girds = row.getElementsByTag("td"); |
||||
|
||||
// 如果这行格子数少于6个,即到了“成绩”的那个格子就没了,那就没啥意义了,直接跳过,不理了
|
||||
if (girds.size() < 6) { |
||||
continue; |
||||
} |
||||
|
||||
ExamInfo examInfo = new ExamInfo(); |
||||
|
||||
// 这段看着震撼,但其实很丑
|
||||
examInfo.setId(JsoupUtil.getElementContext(girds.get(0))); |
||||
|
||||
examInfo.setTerm(JsoupUtil.getElementContext(girds.get(1))); |
||||
examInfo.setCourseNumber(JsoupUtil.getElementContext(girds.get(2))); |
||||
|
||||
examInfo.setCourseName(JsoupUtil.getElementContext(girds.get(3))); |
||||
examInfo.setGroupName(JsoupUtil.getElementContext(girds.get(4))); |
||||
|
||||
examInfo.setScore(JsoupUtil.getElementContext(girds.get(5))); |
||||
examInfo.setFlag(JsoupUtil.getElementContext(girds.get(6))); |
||||
examInfo.setCredit(JsoupUtil.getElementContext(girds.get(7))); |
||||
examInfo.setCourseHours(JsoupUtil.getElementContext(girds.get(8))); |
||||
examInfo.setGradePoint(JsoupUtil.getElementContext(girds.get(9))); |
||||
|
||||
examInfo.setEvaluateMethod(JsoupUtil.getElementContext(girds.get(11))); |
||||
examInfo.setKind(JsoupUtil.getElementContext(girds.get(12))); |
||||
examInfo.setCourseKind(JsoupUtil.getElementContext(girds.get(13))); |
||||
|
||||
examInfos.add(examInfo); |
||||
} |
||||
} catch (Exception e) { |
||||
log.warn("解析成绩页面时发生错误:{}", e.getMessage()); |
||||
log.warn("终止解析,返回已解析数据"); |
||||
} |
||||
|
||||
return examInfos; |
||||
} |
||||
} |
||||
|
||||
final class ExamInfoXpath { |
||||
public static final String EXAM_INFO_ROWS_XPATH = "//*[@id=\"dataList\"]/tbody/tr"; |
||||
} |
@ -0,0 +1,72 @@ |
||||
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.util.JsoupUtil; |
||||
import cn.linghang.mywust.model.global.Score; |
||||
import org.jsoup.Jsoup; |
||||
import org.jsoup.nodes.Element; |
||||
import org.jsoup.select.Elements; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class UndergradScoreParser implements Parser<List<Score>> { |
||||
private static final Logger log = LoggerFactory.getLogger(UndergradScoreParser.class); |
||||
|
||||
@Override |
||||
public List<Score> parse(String html) throws ParseException { |
||||
Elements rows = Jsoup.parse(html).selectXpath(UndergradScoreXpath.EXAM_INFO_ROWS_XPATH); |
||||
if (rows.isEmpty()) { |
||||
throw new ParseException(html); |
||||
} |
||||
|
||||
List<Score> scores = new ArrayList<>(rows.size()); |
||||
|
||||
try { |
||||
for (Element row : rows) { |
||||
// 提取出当前行的所有格子
|
||||
Elements girds = row.getElementsByTag("td"); |
||||
|
||||
// 如果这行格子数少于6个,即到了“成绩”的那个格子就没了,那就没啥意义了,直接跳过,不理了
|
||||
if (girds.size() < 6) { |
||||
continue; |
||||
} |
||||
|
||||
Score score = new Score(); |
||||
|
||||
// 这段看着震撼,但其实很丑
|
||||
score.setId(JsoupUtil.getElementContext(girds.get(0))); |
||||
|
||||
score.setTerm(JsoupUtil.getElementContext(girds.get(1))); |
||||
score.setCourseNumber(JsoupUtil.getElementContext(girds.get(2))); |
||||
|
||||
score.setCourseName(JsoupUtil.getElementContext(girds.get(3))); |
||||
score.setGroupName(JsoupUtil.getElementContext(girds.get(4))); |
||||
|
||||
score.setScore(JsoupUtil.getElementContext(girds.get(5))); |
||||
score.setFlag(JsoupUtil.getElementContext(girds.get(6))); |
||||
score.setCredit(JsoupUtil.getElementContext(girds.get(7))); |
||||
score.setCourseHours(JsoupUtil.getElementContext(girds.get(8))); |
||||
score.setGradePoint(JsoupUtil.getElementContext(girds.get(9))); |
||||
|
||||
score.setEvaluateMethod(JsoupUtil.getElementContext(girds.get(11))); |
||||
score.setKind(JsoupUtil.getElementContext(girds.get(12))); |
||||
score.setCourseKind(JsoupUtil.getElementContext(girds.get(13))); |
||||
|
||||
scores.add(score); |
||||
} |
||||
} catch (Exception e) { |
||||
log.warn("解析成绩页面时发生错误:{}", e.getMessage()); |
||||
log.warn("终止解析,返回已解析数据"); |
||||
} |
||||
|
||||
return scores; |
||||
} |
||||
} |
||||
|
||||
final class UndergradScoreXpath { |
||||
public static final String EXAM_INFO_ROWS_XPATH = "//*[@id=\"dataList\"]/tbody/tr"; |
||||
} |
@ -1,27 +1,31 @@ |
||||
package cn.linghang.mywust.core.request.library; |
||||
|
||||
import cn.linghang.mywust.core.api.Library; |
||||
import cn.linghang.mywust.core.api.LibraryUrls; |
||||
import cn.linghang.mywust.core.request.RequestFactory; |
||||
import cn.linghang.mywust.network.entitys.HttpRequest; |
||||
|
||||
public class LibraryRequestFactory extends RequestFactory { |
||||
public static HttpRequest sessionCookieRequest(String serviceTicket) { |
||||
return makeHttpRequest(String.format(Library.LIBRARY_SESSION_COOKIE_API, serviceTicket)); |
||||
return makeHttpRequest(String.format(LibraryUrls.LIBRARY_SESSION_COOKIE_API, serviceTicket)); |
||||
} |
||||
|
||||
public static HttpRequest indexRequest() { |
||||
return makeHttpRequest(Library.LIBRARY_INDEX_URL); |
||||
return makeHttpRequest(LibraryUrls.LIBRARY_INDEX_URL); |
||||
} |
||||
|
||||
public static HttpRequest currentLoanRequest(String cookie) { |
||||
return makeHttpRequest(Library.LIBRARY_CURRENT_LOAN_API, null, cookie); |
||||
return makeHttpRequest(LibraryUrls.LIBRARY_CURRENT_LOAN_API, null, cookie); |
||||
} |
||||
|
||||
public static HttpRequest loanHistoryRequest(String cookie) { |
||||
return makeHttpRequest(Library.LIBRARY_LOAN_HISTORY_API, null, cookie); |
||||
return makeHttpRequest(LibraryUrls.LIBRARY_LOAN_HISTORY_API, null, cookie); |
||||
} |
||||
|
||||
public static HttpRequest overdueSoonRequest(String cookie) { |
||||
return makeHttpRequest(Library.LIBRARY_OVERDUE_SOON_API, null, cookie); |
||||
return makeHttpRequest(LibraryUrls.LIBRARY_OVERDUE_SOON_API, null, cookie); |
||||
} |
||||
|
||||
public static HttpRequest bookInfoRequest(String cookie) { |
||||
return makeHttpRequest(LibraryUrls.LIBRARY_OVERDUE_SOON_API, null, cookie); |
||||
} |
||||
} |
||||
|
@ -1,61 +0,0 @@ |
||||
package cn.linghang.mywust.core.service.auth; |
||||
|
||||
import cn.linghang.mywust.core.api.Bkjx; |
||||
import cn.linghang.mywust.core.api.UnionAuth; |
||||
import cn.linghang.mywust.core.exception.BasicException; |
||||
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory; |
||||
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; |
||||
|
||||
public class JwcLogin { |
||||
private static final Logger log = LoggerFactory.getLogger(JwcLogin.class); |
||||
|
||||
private final Requester requester; |
||||
|
||||
private final UnionLogin unionLogin; |
||||
|
||||
public JwcLogin(Requester requester) { |
||||
this.requester = requester; |
||||
this.unionLogin = new UnionLogin(requester); |
||||
} |
||||
|
||||
public String getLoginCookie(String username, String password, RequestClientOption requestOption) throws IOException, BasicException { |
||||
// 获取service ticket以进行进一步的登录
|
||||
String serviceTicket = unionLogin.getServiceTicket(username, password, UnionAuth.Service.BKJX_SSO_SERVICE, requestOption); |
||||
|
||||
// 获取登录cookie(session)
|
||||
HttpRequest sessionRequest = BkjxRequestFactory.sessionCookieRequest(serviceTicket); |
||||
HttpResponse sessionResponse = requester.get(sessionRequest, requestOption); |
||||
|
||||
String cookies = sessionResponse.getCookies(); |
||||
if (roughCheckCookie(cookies)) { |
||||
throw new BasicException(); |
||||
} |
||||
|
||||
return cookies; |
||||
} |
||||
|
||||
private boolean roughCheckCookie(String cookies) { |
||||
return cookies == null || !cookies.contains("JSESSIONID") || !cookies.contains("SERVERID"); |
||||
} |
||||
|
||||
private static final int COOKIES_ERROR_RESPONSE_LENGTH = |
||||
("<script languge='javascript'>window.location.href='https://auth.wust.edu.cn/lyuapServer/login?service=http%3A%2F%2Fbkjx.wust.edu.cn%2Fjsxsd%2Fframework%2FblankPage.jsp'</script>") |
||||
.length(); |
||||
|
||||
public boolean checkCookies(String cookies, RequestClientOption option) throws IOException { |
||||
HttpRequest testRequest = BkjxRequestFactory.makeHttpRequest(Bkjx.BKJX_TEST_API, null, cookies); |
||||
HttpResponse testResponse = requester.get(testRequest, option); |
||||
|
||||
// 判断响应长度是否为这么多个字,登录跳转响应长度
|
||||
// 这种办法虽然在极端情况下可能会出错(而且还挺蠢的),但是是最快的办法中比较准确的了
|
||||
return testResponse.getBody().length != COOKIES_ERROR_RESPONSE_LENGTH; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,116 @@ |
||||
package cn.linghang.mywust.core.service.auth; |
||||
|
||||
import cn.linghang.mywust.core.api.UndergradUrls; |
||||
import cn.linghang.mywust.core.api.UnionAuthUrls; |
||||
import cn.linghang.mywust.core.exception.ApiException; |
||||
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory; |
||||
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 cn.linghang.mywust.util.PasswordEncoder; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class UndergraduateLogin { |
||||
private static final Logger log = LoggerFactory.getLogger(UndergraduateLogin.class); |
||||
|
||||
private final Requester requester; |
||||
|
||||
private final UnionLogin unionLogin; |
||||
|
||||
public UndergraduateLogin(Requester requester) { |
||||
this.requester = requester; |
||||
this.unionLogin = new UnionLogin(requester); |
||||
} |
||||
|
||||
public String getLoginCookie(String username, String password, RequestClientOption requestOption) throws IOException, ApiException { |
||||
// 获取service ticket以进行进一步的登录
|
||||
String serviceTicket = unionLogin.getServiceTicket(username, password, UnionAuthUrls.Service.BKJX_SSO_SERVICE, requestOption); |
||||
|
||||
// 获取登录cookie(session)
|
||||
HttpRequest sessionRequest = BkjxRequestFactory.sessionCookieRequest(serviceTicket); |
||||
HttpResponse sessionResponse = requester.get(sessionRequest, requestOption); |
||||
|
||||
String cookies = sessionResponse.getCookies(); |
||||
if (!roughCheckCookie(cookies)) { |
||||
log.error("[mywust]: Cookie粗查不通过:{}", cookies); |
||||
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION, "登录获取的Cookie无效"); |
||||
} |
||||
|
||||
// 检查Cookie是否真正可用,同时请求一次任意接口使后续接口能够正确响应
|
||||
// 拿到Cookie后调用的第一个接口会产生302/301跳转,需要再次调用才能正确响应
|
||||
if (!checkCookies(cookies, requestOption)) { |
||||
log.warn("[mywust]: Cookie检查不通过:{}", cookies); |
||||
} |
||||
|
||||
return cookies; |
||||
} |
||||
|
||||
/** |
||||
* <p>旧版的登录方式,既相当于直接登录<a href="http://bkjx.wust.edu.cn">bkjx系统</a>,不建议使用</p> |
||||
* <p>注意,这种登录方式的密码和新版可能是不一样的</p> |
||||
* <p>不过不论使用哪种登录方式获取到的cookie都是可用的</p> |
||||
* |
||||
* @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时发生错误"); |
||||
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION); |
||||
} |
||||
|
||||
String dataString = new String(dataStringResponse.getBody()); |
||||
|
||||
// 获取登录ticket
|
||||
String encoded = PasswordEncoder.legacyPassword(username, password, dataString); |
||||
HttpRequest ticketRequest = BkjxRequestFactory.Legacy.ticketRedirectRequest(encoded); |
||||
ticketRequest.setCookies(dataStringResponse.getCookies()); |
||||
|
||||
HttpResponse ticketResponse = requester.post(ticketRequest, requestOption); |
||||
if (ticketResponse.getBody() == null) { |
||||
log.warn("[mywust]: 本科教学系统旧版登录方式:获取登录ticket时发生错误"); |
||||
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION); |
||||
} |
||||
|
||||
// 使用跳转得到的链接获取cookies
|
||||
String sessionRedirect = ticketResponse.getHeaders().get("Location"); |
||||
if (sessionRedirect == null) { |
||||
throw new ApiException(ApiException.Code.BKJX_LEGACY_LOGIN_PASSWORD_WRONG); |
||||
} |
||||
|
||||
HttpRequest sessionRequest = BkjxRequestFactory.makeHttpRequest(sessionRedirect); |
||||
HttpResponse sessionResponse = requester.get(sessionRequest, requestOption); |
||||
|
||||
String cookies = sessionResponse.getCookies(); |
||||
if (checkCookies(cookies, requestOption)) { |
||||
log.warn("[mywust]: Cookie检查不通过:{}", cookies); |
||||
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION, "登录获取的Cookie无效"); |
||||
} |
||||
|
||||
return cookies; |
||||
} |
||||
|
||||
private boolean roughCheckCookie(String cookies) { |
||||
return cookies != null && cookies.contains("JSESSIONID") && cookies.contains("SERVERID"); |
||||
} |
||||
|
||||
private static final int COOKIES_ERROR_RESPONSE_LENGTH = |
||||
("<script languge='javascript'>window.location.href='https://auth.wust.edu.cn/lyuapServer/login?service=http%3A%2F%2Fbkjx.wust.edu.cn%2Fjsxsd%2Fframework%2FblankPage.jsp'</script>") |
||||
.length(); |
||||
|
||||
public boolean checkCookies(String cookies, RequestClientOption option) throws IOException { |
||||
HttpRequest testRequest = BkjxRequestFactory.makeHttpRequest(UndergradUrls.BKJX_TEST_API, null, cookies); |
||||
HttpResponse testResponse = requester.get(testRequest, option); |
||||
|
||||
// 判断响应长度是否为这么多个字,登录跳转响应长度
|
||||
// 这种办法虽然在极端情况下可能会出错(而且还挺蠢的),但是是最快的办法中比较准确的了
|
||||
return Math.abs(COOKIES_ERROR_RESPONSE_LENGTH - testResponse.getBody().length) > 8; |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
package cn.linghang.mywust.core.service.captcha.solver; |
||||
|
||||
import cn.linghang.mywust.captcha.SolvedImageCaptcha; |
||||
import cn.linghang.mywust.captcha.UnsolvedImageCaptcha; |
||||
import cn.linghang.mywust.core.exception.ApiException; |
||||
import cn.linghang.mywust.core.request.RequestFactory; |
||||
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.Base64; |
||||
|
||||
public class DdddOcrCaptchaSolver implements CaptchaSolver { |
||||
private final String baseUrl; |
||||
|
||||
private final Requester requester; |
||||
|
||||
public DdddOcrCaptchaSolver(String baseUrl, Requester requester) { |
||||
this.baseUrl = baseUrl; |
||||
this.requester = requester; |
||||
} |
||||
|
||||
@Override |
||||
public SolvedImageCaptcha solve(UnsolvedImageCaptcha unsolvedImageCaptcha) throws ApiException { |
||||
try { |
||||
SolvedImageCaptcha solvedImageCaptcha = new SolvedImageCaptcha(unsolvedImageCaptcha); |
||||
|
||||
String result = this.ocr(unsolvedImageCaptcha.getImage()); |
||||
solvedImageCaptcha.setResult(result); |
||||
return solvedImageCaptcha; |
||||
} catch (IOException e) { |
||||
throw new ApiException(ApiException.Code.NETWORK_EXCEPTION); |
||||
} |
||||
} |
||||
|
||||
private String ocr(byte[] data) throws IOException { |
||||
HttpRequest request = RequestFactory.makeHttpRequest(baseUrl + "/ocr/b64/text", Base64.getEncoder().encode(data)); |
||||
HttpResponse response = requester.post(request); |
||||
|
||||
return response.getStringBody(); |
||||
} |
||||
} |
@ -1,11 +0,0 @@ |
||||
package cn.linghang.mywust.core.service.captcha.solver; |
||||
|
||||
import cn.linghang.mywust.captcha.SolvedImageCaptcha; |
||||
import cn.linghang.mywust.captcha.UnsolvedImageCaptcha; |
||||
|
||||
public class LocalPaddleOcrCaptchaSolver implements CaptchaSolver { |
||||
@Override |
||||
public SolvedImageCaptcha solve(UnsolvedImageCaptcha unsolvedImageCaptcha) { |
||||
return null; |
||||
} |
||||
} |
@ -1,33 +0,0 @@ |
||||
package cn.linghang.mywust.core.service.undergraduate; |
||||
|
||||
import cn.linghang.mywust.core.exception.ApiException; |
||||
import cn.linghang.mywust.core.exception.ParseException; |
||||
import cn.linghang.mywust.core.parser.undergraduate.CourseTableParser; |
||||
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory; |
||||
import cn.linghang.mywust.model.global.Course; |
||||
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 CourseTableApiService extends UndergraduateApiService { |
||||
|
||||
public CourseTableApiService(Requester requester) { |
||||
super(requester); |
||||
} |
||||
|
||||
public String getCourseTablePage(String term, String cookies, RequestClientOption requestClientOption) throws IOException, ApiException { |
||||
HttpRequest request = BkjxRequestFactory.courseTablePageRequest(term, cookies); |
||||
HttpResponse response = requester.post(request, requestClientOption); |
||||
|
||||
super.checkResponse(response); |
||||
|
||||
return new String(response.getBody()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,49 @@ |
||||
package cn.linghang.mywust.core.service.undergraduate; |
||||
|
||||
import cn.linghang.mywust.core.exception.ApiException; |
||||
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory; |
||||
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.Map; |
||||
|
||||
public class UndergradCourseTableApiService extends UndergradApiServiceBase { |
||||
|
||||
private static final String[] NECESSARY_PARAMS = {"term"}; |
||||
|
||||
public UndergradCourseTableApiService(Requester requester) { |
||||
super(requester); |
||||
} |
||||
|
||||
@Override |
||||
public String getPage(String cookie, Map<String, String> params, RequestClientOption option) throws ApiException, IOException { |
||||
for (String key : NECESSARY_PARAMS) { |
||||
if (params.get(key) == null) { |
||||
throw new ApiException(ApiException.Code.PARAM_WRONG_EXCEPTION); |
||||
} |
||||
} |
||||
|
||||
return this.getPage(params.get(NECESSARY_PARAMS[0]), cookie, option); |
||||
} |
||||
|
||||
@Override |
||||
public String getPage(String cookie, Map<String, String> params) throws ApiException, IOException { |
||||
return this.getPage(cookie, params, null); |
||||
} |
||||
|
||||
public String getPage(String term, String cookies, RequestClientOption requestClientOption) throws IOException, ApiException { |
||||
HttpRequest request = BkjxRequestFactory.courseTablePageRequest(term, cookies); |
||||
HttpResponse response = requester.post(request, requestClientOption); |
||||
|
||||
super.checkResponse(response); |
||||
|
||||
return new String(response.getBody()); |
||||
} |
||||
|
||||
public String getPage(String term, String cookies) throws IOException, ApiException { |
||||
return getPage(term, cookies, null); |
||||
} |
||||
} |
@ -1,27 +1,32 @@ |
||||
package cn.linghang.mywust.core.service.undergraduate; |
||||
|
||||
import cn.linghang.mywust.core.exception.ApiException; |
||||
import cn.linghang.mywust.core.exception.ParseException; |
||||
import cn.linghang.mywust.core.parser.undergraduate.ExamInfoParser; |
||||
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory; |
||||
import cn.linghang.mywust.model.global.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; |
||||
import java.util.Map; |
||||
|
||||
public class ExamInfoApiService extends UndergraduateApiService { |
||||
public class UndergradScoreApiService extends UndergradApiServiceBase { |
||||
|
||||
public ExamInfoApiService(Requester requester) { |
||||
public UndergradScoreApiService(Requester requester) { |
||||
super(requester); |
||||
} |
||||
|
||||
public String getExamInfoPage(String cookies, RequestClientOption requestClientOption) throws IOException, ApiException { |
||||
@Override |
||||
public String getPage(String cookie, Map<String, String> params, RequestClientOption option) throws ApiException, IOException { |
||||
return this.getPage(cookie, option); |
||||
} |
||||
|
||||
@Override |
||||
public String getPage(String cookie, Map<String, String> params) throws ApiException, IOException { |
||||
return this.getPage(cookie, params, null); |
||||
} |
||||
|
||||
public String getPage(String cookies, RequestClientOption requestClientOption) throws IOException, ApiException { |
||||
HttpRequest request = BkjxRequestFactory.examScoreInfoRequest(cookies, "", "", ""); |
||||
HttpResponse response = requester.post(request, requestClientOption); |
||||
|
@ -0,0 +1,16 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-model</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>1.18.22</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,16 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-network-httpclient</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>1.18.22</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,40 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-network-okhttp</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>com.squareup.okhttp3</groupId> |
||||
<artifactId>okhttp</artifactId> |
||||
<version>3.14.9</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-api</artifactId> |
||||
<version>1.7.36</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-network</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-util</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>1.18.22</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,22 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-network</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-util</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>1.18.22</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -1,27 +1,105 @@ |
||||
package cn.linghang.mywust.network; |
||||
|
||||
import lombok.Builder; |
||||
import lombok.Data; |
||||
|
||||
@Data |
||||
public class RequestClientOption { |
||||
private Proxy proxy; |
||||
private long timeout; |
||||
private boolean fallowUrlRedirect = false; |
||||
private boolean fallowUrlRedirect; |
||||
|
||||
private boolean ignoreSSLError; |
||||
|
||||
@Data |
||||
@Builder |
||||
public static class Proxy { |
||||
private String address; |
||||
private int port; |
||||
} |
||||
|
||||
public RequestClientOption() { |
||||
this.proxy = null; |
||||
this.timeout = 5; |
||||
this.fallowUrlRedirect = false; |
||||
this.ignoreSSLError = true; |
||||
} |
||||
|
||||
public RequestClientOption(Proxy proxy, long timeout, boolean fallowUrlRedirect, boolean ignoreSSLError) { |
||||
this.proxy = proxy; |
||||
this.timeout = timeout; |
||||
this.fallowUrlRedirect = fallowUrlRedirect; |
||||
this.ignoreSSLError = ignoreSSLError; |
||||
} |
||||
|
||||
public static final RequestClientOption DEFAULT_OPTION = newDefaultOption(); |
||||
|
||||
private static RequestClientOption newDefaultOption() { |
||||
RequestClientOption option = new RequestClientOption(); |
||||
option.setTimeout(5); |
||||
option.setProxy(null); |
||||
option.setFallowUrlRedirect(false); |
||||
return new ConstantRequestClientOption(); |
||||
} |
||||
|
||||
/** |
||||
* 常量化的RequestClientOption,对其使用setter时不会起任何作用 |
||||
*/ |
||||
public static class ConstantRequestClientOption extends RequestClientOption { |
||||
@Override |
||||
public Proxy getProxy() { |
||||
return super.getProxy(); |
||||
} |
||||
|
||||
@Override |
||||
public long getTimeout() { |
||||
return super.getTimeout(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isFallowUrlRedirect() { |
||||
return super.isFallowUrlRedirect(); |
||||
} |
||||
|
||||
@Override |
||||
public void setProxy(Proxy proxy) {} |
||||
|
||||
@Override |
||||
public void setTimeout(long timeout) {} |
||||
|
||||
@Override |
||||
public void setFallowUrlRedirect(boolean fallowUrlRedirect) {} |
||||
} |
||||
|
||||
public static RequestClientOptionBuilder builder() { |
||||
return new RequestClientOptionBuilder(); |
||||
} |
||||
|
||||
public static final class RequestClientOptionBuilder { |
||||
private final RequestClientOption requestClientOption; |
||||
|
||||
private RequestClientOptionBuilder() { |
||||
requestClientOption = new RequestClientOption(); |
||||
} |
||||
|
||||
public RequestClientOptionBuilder proxy(Proxy proxy) { |
||||
requestClientOption.setProxy(proxy); |
||||
return this; |
||||
} |
||||
|
||||
public RequestClientOptionBuilder timeout(long timeout) { |
||||
requestClientOption.setTimeout(timeout); |
||||
return this; |
||||
} |
||||
|
||||
public RequestClientOptionBuilder fallowUrlRedirect(boolean fallowUrlRedirect) { |
||||
requestClientOption.setFallowUrlRedirect(fallowUrlRedirect); |
||||
return this; |
||||
} |
||||
|
||||
public RequestClientOptionBuilder ignoreSSLError(boolean ignoreSSLError) { |
||||
requestClientOption.setIgnoreSSLError(ignoreSSLError); |
||||
return this; |
||||
} |
||||
|
||||
return option; |
||||
public RequestClientOption build() { |
||||
return requestClientOption; |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,12 @@ |
||||
import cn.linghang.mywust.core.exception.ParseException; |
||||
import cn.linghang.mywust.core.parser.undergraduate.ExamInfoParser; |
||||
import org.jsoup.Jsoup; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class ParseTest { |
||||
public static void main(String[] args) throws IOException, ParseException { |
||||
ExamInfoParser parser = new ExamInfoParser(); |
||||
System.out.println(parser.parse(Jsoup.connect("http://127.0.0.1/a.html").get().toString())); |
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>cn.linghang</groupId> |
||||
<artifactId>mywust-util</artifactId> |
||||
<version>0.0.1-fixed</version> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>commons-codec</groupId> |
||||
<artifactId>commons-codec</artifactId> |
||||
<version>1.15</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.google.guava</groupId> |
||||
<artifactId>guava</artifactId> |
||||
<version>31.1-jre</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>1.18.22</version> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
Loading…
Reference in new issue