[积累性更新] 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; | ||||
| 
 | ||||
| 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,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; | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| @ -1,27 +1,70 @@ | ||||
| package cn.linghang.mywust.network; | ||||
| 
 | ||||
| import lombok.Builder; | ||||
| import lombok.Data; | ||||
| 
 | ||||
| @Data | ||||
| @Builder | ||||
| 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) {} | ||||
| 
 | ||||
|         return option; | ||||
|         @Override | ||||
|         public void setFallowUrlRedirect(boolean fallowUrlRedirect) {} | ||||
|     } | ||||
| } | ||||
|  | ||||
					Loading…
					
					
				
		Reference in new issue