福大图书馆预约的流程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实现的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程