[积累性更新] 1.统一认证登录:新增部分错误信息; 2.重命名部分类和方法; 3.network模块部分方法新增一些参数,部分实体类新增builder,方便使用; 4.研究生部分新增简单的Ddddocr验证码处理器; 5.SimpleOkhttpRequester新增CookieJar支持;
parent
79c6659509
commit
24c23c33e1
@ -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; |
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_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"; |
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; |
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_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"; |
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; |
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_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"; |
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; |
package cn.linghang.mywust.core.api; |
||||||
|
|
||||||
public class UnionAuth { |
public class UnionAuthUrls { |
||||||
/** |
/** |
||||||
* 统一认证登录验证的api地址,请求之后可进一步获取service ticket来对具体的服务进行登录获取Cookies |
* 统一认证登录验证的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; |
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.core.request.RequestFactory; |
||||||
import cn.linghang.mywust.network.entitys.HttpRequest; |
import cn.linghang.mywust.network.entitys.HttpRequest; |
||||||
|
|
||||||
public class LibraryRequestFactory extends RequestFactory { |
public class LibraryRequestFactory extends RequestFactory { |
||||||
public static HttpRequest sessionCookieRequest(String serviceTicket) { |
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() { |
public static HttpRequest indexRequest() { |
||||||
return makeHttpRequest(Library.LIBRARY_INDEX_URL); |
return makeHttpRequest(LibraryUrls.LIBRARY_INDEX_URL); |
||||||
} |
} |
||||||
|
|
||||||
public static HttpRequest currentLoanRequest(String cookie) { |
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) { |
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) { |
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,62 +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.ApiException; |
|
||||||
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, ApiException { |
|
||||||
// 获取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 ApiException(ApiException.Code.UNKNOWN_EXCEPTION); |
|
||||||
} |
|
||||||
|
|
||||||
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,110 @@ |
|||||||
|
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 (checkCookies(cookies, requestOption)) { |
||||||
|
log.warn("[mywust]: Cookie检查不通过:{}", cookies); |
||||||
|
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION, "登录获取的Cookie无效"); |
||||||
|
} |
||||||
|
|
||||||
|
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; |
package cn.linghang.mywust.core.service.undergraduate; |
||||||
|
|
||||||
import cn.linghang.mywust.core.exception.ApiException; |
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.core.request.undergrade.BkjxRequestFactory; |
||||||
import cn.linghang.mywust.model.global.ExamInfo; |
|
||||||
import cn.linghang.mywust.network.RequestClientOption; |
import cn.linghang.mywust.network.RequestClientOption; |
||||||
import cn.linghang.mywust.network.Requester; |
import cn.linghang.mywust.network.Requester; |
||||||
import cn.linghang.mywust.network.entitys.HttpRequest; |
import cn.linghang.mywust.network.entitys.HttpRequest; |
||||||
import cn.linghang.mywust.network.entitys.HttpResponse; |
import cn.linghang.mywust.network.entitys.HttpResponse; |
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import java.io.IOException; |
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); |
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, "", "", ""); |
HttpRequest request = BkjxRequestFactory.examScoreInfoRequest(cookies, "", "", ""); |
||||||
HttpResponse response = requester.post(request, requestClientOption); |
HttpResponse response = requester.post(request, requestClientOption); |
||||||
|
|
@ -1,27 +1,70 @@ |
|||||||
package cn.linghang.mywust.network; |
package cn.linghang.mywust.network; |
||||||
|
|
||||||
|
import lombok.Builder; |
||||||
import lombok.Data; |
import lombok.Data; |
||||||
|
|
||||||
@Data |
@Data |
||||||
|
@Builder |
||||||
public class RequestClientOption { |
public class RequestClientOption { |
||||||
private Proxy proxy; |
private Proxy proxy; |
||||||
private long timeout; |
private long timeout; |
||||||
private boolean fallowUrlRedirect = false; |
private boolean fallowUrlRedirect; |
||||||
|
|
||||||
|
private boolean ignoreSSLError; |
||||||
|
|
||||||
@Data |
@Data |
||||||
|
@Builder |
||||||
public static class Proxy { |
public static class Proxy { |
||||||
private String address; |
private String address; |
||||||
private int port; |
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(); |
public static final RequestClientOption DEFAULT_OPTION = newDefaultOption(); |
||||||
|
|
||||||
private static RequestClientOption newDefaultOption() { |
private static RequestClientOption newDefaultOption() { |
||||||
RequestClientOption option = new RequestClientOption(); |
return new ConstantRequestClientOption(); |
||||||
option.setTimeout(5); |
} |
||||||
option.setProxy(null); |
|
||||||
option.setFallowUrlRedirect(false); |
/** |
||||||
|
* 常量化的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) {} |
||||||
|
|
||||||
return option; |
@Override |
||||||
|
public void setFallowUrlRedirect(boolean fallowUrlRedirect) {} |
||||||
} |
} |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue