福大图书馆预约的流程Java实现
2022/6/30 1:20:21
本文主要是介绍福大图书馆预约的流程Java实现,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
提示信息
1.登录需要用到csrf防护的参数,需要手动get kjgl.fzu.edu.cn后获取。参数在dom中的id是SYNCHRONIZE_TOKEN和SYNCHRONIZE_URI。可以用jsoup(python可以用beautifulsoup)通过getElementById获取它的attr的value。记住这两个参数,后面所有的post请求都要用到。(后续请求的时候会不会变化不太清楚 建议每次请求前都get一遍真实情况下的页面获取这两参数)。这一步同时会获得一个cookie内含JSESSION ID,记得保存备用。postman可能不好解析dom文档,我不清楚相关的函数。
2.获取到以上两个参数后就可以进行登录操作了,在讲登录操作之前,先讲验证码。验证码是点击图中汉字的类型。验证码请求分为以下几个部分:
第一步 先GET simpleCaptcha/chCaptcha
,这一步操作是否必须未知。在浏览器上get这个页面主要是获取验证码相关的js和html。
第二步 post /cap/captcha
参数有两个一个username一个userId,这两个参数都可以为空,或者你愿意往username里塞你的登录用户名也可以,不影响。这一步会返回一个token用于验证码图片请求,称呼其为captoken.
第三步 get /cap/captchaImg/2
参数有两个 一个为token填入上面的captoken,还有一个r为0-1之间的随机数 这一步获取到验证码中要点击的汉字的图片,这个验证码OCR难度比较低。要点击汉字是两个。这一步OCR出来的文字可以为后面的识别降低很大阻碍。
第四步 get /cap/captchaImg/1
参数同上。这一步获取到要被点击的图片主体。请注意这个是最难的部分,因为这个图片的背景复杂度高,其中的字体,部分会是手写体/其他干扰,把这个图片弄到百度ai识图高精度版带坐标以及阿里云ai识图高精度版中,准确率非常低,汉字位置都不一定识别的出来。倒是有高人提供了验证码识别服务,估计是他们自己训练的模型吧,我试用后识别率接近100%,但是一问报价8k,这个级别的项目8k多少太贵了,企业爬别人家网站用还差不多。。。
注意第三步和第四步请求间隔不能太长,否则其中之一请求会返回为空!若用postman尝试记得写脚本让两请求一起发送。
第五步 获取到图片上相关汉字的坐标(可以用PS的信息或者imageglass的取色工具或者qq截图之类),记得坐标尽量偏下一点(玄学),封装成如下json形式:
[{"x"=20,"y"=20},{"x"=20,"y"=20}]
然后用base64编码 编码,然后GET http://kjgl.fzu.edu.cn/cap/checkCaptcha
参数为a(坐标的base64编码结果),token(上面captoken),userId(可以为空)
返回OK则验证成功,FAIL则失败。ok后的过期时间较长。注意等太久才请求,不论坐标是否正确均会直接fail。
第六步 验证码成功后post登录链接 为/login
参数为上面提到的synchronize_token和synchronize_uri,这一步uri固定为/login。还有username和password参数(明文),一个authid参数,这个authid参数就是上面的captoken。
这一步请求注意:"Origin", "http://kjgl.fzu.edu.cn"这个请求头必须带(或者还有其他头,建议看代码看我带的头,实测无问题)。否则!!不论是否正确,一律会给你重定向回登录页!并且没有错误提示!!
这一步请求成功若重定向至kjgl.fzu.edu.cn则登录成功。注意:这一步返回一个钓鱼cookie,value为deleteme,不要保存这个cookie,否则会导致后续请求失败。后续所有请求必须带最开始获取的JSESSIONID的那个cookie!!
第七步 get /map 这一步会进入到选座界面。同样的这个页面也有synchronize_token和_uri,注意保存。这一步后就可以post /selfRes进行选座了。选座有如下参数:
'authid': '验证码的token,请求方式同登录,这一步可能要带上你的username',
'date': yy-MM-dd形式,
'end': 结束时间,分钟数 8:30就是8*60+30,
'seat': 座位号,没有特别和实际座位号对应关系,只能自行查看相应座位的号码,
'start': 开始时间 为分钟数,
'SYNCHRONIZER_TOKEN':同登录请求 ,
'SYNCHRONIZER_URI': 同登录请求,
请求成功后即选座成功。
取消选座(我的选座页面里相应按钮的href,直接get不用验证码)、续约等自行研究,本人无兴趣也无动力去研究后续内容。
以下为本人测试用代码,使用到fastjson、jsoup、okhttp三个依赖,环境为Java8.
package com.jessie.fzuseats; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import okhttp3.*; import org.jetbrains.annotations.NotNull; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import java.io.FileOutputStream; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Base64; import java.util.List; import java.util.Scanner; public class captChaTest { public static String JSESSIONID = ""; public static String authid = "-1"; public static String syncToken=""; public static String syncUri=""; public static OkHttpClient okHttpClient = new OkHttpClient.Builder().followRedirects(false).cookieJar(new CookieJar() { List<Cookie> list; @Override public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) { if(list.get(0).value().equals("deleteMe")){ System.out.println("钓鱼的!无视!"); return; } this.list = list; System.out.println("cookieList:" + list); JSESSIONID = "JSESSIONID=" + list.get(0).value(); System.out.println("JSESSIONID= " + JSESSIONID); } @NotNull @Override public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) { if (list == null) { return new ArrayList<>(); } return list; } }).build(); public static void main(String[] args) { try { loginKJGL(); orderSeat(); } catch (Exception e) { e.printStackTrace(); } } public static void getCaptcha() throws Exception { Headers headers = new Headers.Builder() .add("Accept", "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8") .add("Accept-Encoding", "gzip, deflate") .add("Host", "kjgl.fzu.edu.cn") .add("Upgrade-Insecure-Requests", "1") .add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0").build(); Request request00 = new Request.Builder().url("http://kjgl.fzu.edu.cn/simpleCaptcha/chCaptcha").headers(headers).build(); Response respSimpleCaptcha = okHttpClient.newCall(request00).execute();//这一步可能没法省略,否则可能过不了后台 RequestBody formBody0 = new FormBody.Builder().add("userId", "").add("username", "").build(); Request request0 = new Request.Builder().url("http://kjgl.fzu.edu.cn/cap/captcha").headers(headers) .post(formBody0) .build(); Response respCaptcha = okHttpClient.newCall(request0).execute(); String respBody = respCaptcha.body().string(); System.out.println(respBody); String captchaToken = JSON.parseObject(respBody).getString("token"); System.out.println("captchaToken:" + captchaToken); Request request01 = new Request.Builder().url("http://kjgl.fzu.edu.cn/cap/captchaImg/2" + "?token=" + captchaToken + "&r=" + Math.random()) .headers(headers) .build(); Request request02 = new Request.Builder().url("http://kjgl.fzu.edu.cn/cap/captchaImg/1" + "?token=" + captchaToken + "&r=" + Math.random()) .headers(headers) .build(); Response cap1 = okHttpClient.newCall(request01).execute(); FileOutputStream fileOutputStream = new FileOutputStream("D:\\cap1.jpg"); fileOutputStream.write(cap1.body().bytes()); Response cap2 = okHttpClient.newCall(request02).execute(); FileOutputStream fileOutputStream2 = new FileOutputStream("D:\\cap2.jpg"); fileOutputStream2.write(cap2.body().bytes()); System.out.println("请输入坐标"); int x1, y1, x2, y2; Scanner in = new Scanner(System.in); x1 = in.nextInt(); y1 = in.nextInt(); x2 = in.nextInt(); y2 = in.nextInt(); JSONArray jsonArray = new JSONArray(); JSONObject jsonObject = new JSONObject(); jsonObject.put("x", x1); jsonObject.put("y", y1); JSONObject jsonObject2 = new JSONObject(); jsonObject2.put("x", x2); jsonObject2.put("y", y2); jsonArray.add(jsonObject); jsonArray.add(jsonObject2); System.out.println(jsonArray); Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(jsonArray.toString().getBytes()); System.out.println(s); Request request03 = new Request.Builder().url("http://kjgl.fzu.edu.cn/cap/checkCaptcha" + "?a=" + s + "&token=" + captchaToken + "&userId=") .headers(headers) .addHeader("Referer", "http://kjgl.fzu.edu.cn/simpleCaptcha/chCaptcha") .build(); Response execute03 = okHttpClient.newCall(request03).execute(); System.out.println("message:" + execute03.message()); ResponseBody resp03 = execute03.body(); System.out.println(execute03.code()); if (resp03.string().contains("OK")) { System.out.println("成功"); authid = captchaToken; } else { System.out.println("可能发生错误.."); String res = resp03.string(); System.out.println(res); System.out.println("正在重新获取captcha........"); getCaptcha();//重新获取captcha } } public static void loginKJGL() throws Exception { Request request = new Request.Builder().url("http://kjgl.fzu.edu.cn/login"). addHeader("Accept", "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8") .addHeader("Accept-Encoding", "gzip, deflate") .addHeader("Host", "kjgl.fzu.edu.cn") .addHeader("Upgrade-Insecure-Requests", "1") .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0") .build(); Response response = okHttpClient.newCall(request).execute(); if (response.isSuccessful()) { Headers headers = response.headers(); List<String> cookies = headers.values("Set-Cookie"); System.out.println("Begin"); for (String x : cookies) { System.out.println(x); } System.out.println("HEADER"); System.out.println(headers.toString()); //此时还没有cookie生成 } ResponseBody body = response.body(); if (body == null) { throw new NullPointerException("返回结果为空!"); } Document document = Jsoup.parse(body.string()); Element synchronizer_token = document.getElementById("SYNCHRONIZER_TOKEN"); Element synchronizer_uri = document.getElementById("SYNCHRONIZER_URI"); String synTokenValue = synchronizer_token.attributes().get("value"); String synTokenUri = synchronizer_uri.attributes().get("value"); System.out.println(synTokenValue + " NEXT: " + synTokenUri); getCaptcha(); if (authid.equals("-1")) { System.out.println("authid错误"); System.exit(0); } else { System.out.println("AUTH ID " + authid); System.out.println("JSESSIONID " + JSESSIONID); } RequestBody formBody = new FormBody.Builder().add("authid", authid). add("password", "Ljn231596") .add("SYNCHRONIZER_TOKEN", synTokenValue) .add("SYNCHRONIZER_URI", "/login") .add("username", "1130319024101").build(); Request request2 = new Request.Builder().url("http://kjgl.fzu.edu.cn/auth/signIn"). addHeader("Accept", "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8") .addHeader("Accept-Encoding", "gzip, deflate") .addHeader("Host", "kjgl.fzu.edu.cn") .addHeader("Upgrade-Insecure-Requests", "1") .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0") // .addHeader("Cookie","JSESSIONID="+JSESSIONID) .addHeader("Referer", "http://kjgl.fzu.edu.cn/login?targetUri=%2F") .addHeader("Content-Type", "application/x-www-form-urlencoded") .addHeader("Connection", "keep-alive") .addHeader("Origin", "http://kjgl.fzu.edu.cn") .post(formBody) .build(); System.out.println("REQUEST2 " + request2); System.out.println(request2.headers()); Response response2 = okHttpClient.newCall(request2).execute(); int code = response2.code(); ResponseBody responseBody = response2.body(); String resp2 = responseBody.string(); System.out.println("code=" + code); System.out.println("resp2:Headers:" + response2.headers()); // System.out.println(resp2); // 成功获取到下一个页面 即预约页面 if (!resp2.contains("请输入座位号")) { // System.out.println(resp2); System.out.println("失败#############################################"); } else { System.out.println(resp2); System.out.println("success"); } Request request23 = new Request.Builder().url("http://kjgl.fzu.edu.cn/") .addHeader("Accept", "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8") .addHeader("Accept-Encoding", "gzip, deflate") .addHeader("Host", "kjgl.fzu.edu.cn") .addHeader("Upgrade-Insecure-Requests", "1") .addHeader("Connection","keep-alive") .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0") // .addHeader("Cookie",JSESSIONID) .addHeader("Referer", "http://kjgl.fzu.edu.cn/login?targetUri=%2F") .addHeader("Upgrade-Insecure-Requests", "1").build(); Response resp23 = okHttpClient.newCall(request23).execute(); System.out.println("REQUEST23 "+resp23.body().string()); Request request3 = new Request.Builder().url("http://kjgl.fzu.edu.cn/map"). addHeader("Accept", "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8") .addHeader("Accept-Encoding", "gzip, deflate") .addHeader("Host", "kjgl.fzu.edu.cn") .addHeader("Upgrade-Insecure-Requests", "1") .addHeader("Connection","keep-alive") .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0") // .addHeader("Cookie",JSESSIONID) .addHeader("Referer", "http://kjgl.fzu.edu.cn/") .addHeader("Upgrade-Insecure-Requests", "1") .build(); Response response3 = okHttpClient.newCall(request3).execute(); System.out.println(response3.code()); String resp3=response3.body().string(); System.out.println(resp3); Document resp3Docu = Jsoup.parse(resp3); syncToken = resp3Docu.getElementById("SYNCHRONIZER_TOKEN").attributes().get("value"); syncUri = resp3Docu.getElementById("SYNCHRONIZER_URI").attributes().get("value"); //后面orderSeat要用到 } public static void orderSeat() throws Exception{ getCaptcha(); String tomorrowDate= LocalDate.now().plusDays(1).format(DateTimeFormatter.ofPattern("yy-MM-dd")); RequestBody formBody = new FormBody.Builder().add("authid", authid). add("password", "Ljn231596") .add("SYNCHRONIZER_TOKEN", syncToken) .add("SYNCHRONIZER_URI", syncUri)//正常情况下这里为/map .add("date", tomorrowDate) .add("seat", "123456")//这里填写座位号,各seats的实际id需要自行上kjgl的页面按f12去查看 .add("start","480")//8:00 8*60 .add("end","1350")//22:30 22*60+50 .build(); Request orderRequest=new Request.Builder().url("http://kjgl.fzu.edu.cn/selfRes") . addHeader("Accept", "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8") .addHeader("Accept-Encoding", "gzip, deflate") .addHeader("Host", "kjgl.fzu.edu.cn") .addHeader("Upgrade-Insecure-Requests", "1") .addHeader("Connection","keep-alive") .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0") .addHeader("Referer", "http://kjgl.fzu.edu.cn/") .addHeader("Upgrade-Insecure-Requests", "1") .post(formBody).build(); //这一步没有尝试过,失败的同学自行去看下正常流程的,看看少了哪些头补上即可 Response execute = okHttpClient.newCall(orderRequest).execute(); String resp = execute.body().string(); System.out.println(resp); } }
这篇关于福大图书馆预约的流程Java实现的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-04-26敏捷开发:想要快速交付就必须舍弃产品质量?
- 2024-04-26静态代码分析的这些好处,我竟然都不知道?
- 2024-04-26你在测试金字塔的哪一层?(下)
- 2024-04-26快刀斩乱麻,DevOps让代码评审也自动起来
- 2024-04-262024年最好用的10款ER图神器!
- 2024-04-2203-为啥大模型LLM还没能完全替代你?
- 2024-04-2101-大语言模型发展
- 2024-04-17基于SpringWeb MultipartFile文件上传、下载功能
- 2024-04-14个人开发者,Spring Boot 项目如何部署
- 2024-04-14RAG应用开发实战02-相似性检索的关键 - Embedding