福大图书馆预约的流程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,福大,System,addHeader,预约,edu,println,kjgl,out 来源: https://www.cnblogs.com/6543x1/p/16422991.html