一:原理

  • 客户端访问服务器,服务器通过Session对象记录会话,服务器可以指定一个唯一的session ID作为cookie来代表每个客户端,用来识别这个客户端接下来的请求。
  • 我们通过Chrome浏览器进行网页访问时,服务器会在我们第一次请求时就建立会话生成Session对象,然后给我们的浏览器返回该Session ID,并把Session的ID保存在客户机的Cookie中,如图:
  • 我们的每次请求都带上我们的Cookie,就可以实现会话状态的保持。


二:代码

package cn.zyzpp.eduCookie;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

import org.jsoup.Connection;
import org.jsoup.Connection.Method;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
import org.junit.Before;
import org.junit.Test;

import cn.zyzpp.eduCookie2.S;

/**
 * 模拟登录带验证码的教务系统
 *
 * 2018-2-9
 */
public class JsoupSafeCode {
    private String url_safecode = "http://jwxt.qlu.edu.cn/verifycode.servlet?t=0.020974584"; // 验证码
    private String url_encode = "http://jwxt.qlu.edu.cn/Logon.do?method=logon&flag=sess"; // 加密字符串
    private String url_Login = "http://jwxt.qlu.edu.cn/Logon.do?method=logon"; // 登录
    private String username = "";
    private String password = "";
    private String path = JsoupSafeCode.class.getResource("/").getPath().replaceAll("%20", " ") + "safecode.png";
    private Map<String, String> cookie;

    /**
     * 下载验证码
     * 保存Cookie
     * @throws IOException
     */
    public void getSafeCode() throws IOException {
        Response response = Jsoup.connect(url_safecode).ignoreContentType(true) // 获取图片需设置忽略内容类型
                .userAgent("Mozilla").method(Method.GET).timeout(3000).execute();
        cookie = response.cookies();
        byte[] bytes = response.bodyAsBytes();
        Util.saveFile(path, bytes);
        System.out.println("保存验证码到:" + path);
    }

    /**
     * 登录教务系统
     */
    public void initLogin() throws IOException {
        S.print("输入验证码:");
        Scanner scan = new Scanner(System.in);
        String code = scan.next();
        try {
            Map<String, String> data = new HashMap<String, String>();
            data.put("view", "1");
            data.put("encoded", getEncoded());
            data.put("RANDOMCODE", code);
            Connection connect = Jsoup.connect(url_Login)
                    .header("Accept",
                            "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
                    .userAgent("Mozilla").method(Method.POST).data(data).timeout(3000);
            for (Map.Entry<String, String> entry : cookie.entrySet()) {
                connect.cookie(entry.getKey(), entry.getValue());
            }
            Response response = connect.execute();
            S.println(response.parse().text().toString());
        } catch (IOException e) {

        }
    }

    /**
     * 加密参数(依具体环境而定,加密算法一般在JS中获得)
     */
    public String getEncoded() {
        try {
            Connection connect = Jsoup.connect(url_encode)
                    .header("Accept",
                            "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
                    .userAgent("Mozilla").method(Method.POST).timeout(3000);
            for (Map.Entry<String, String> entry : cookie.entrySet()) {
                connect.cookie(entry.getKey(), entry.getValue());
            }
            Response response = connect.execute();
            String dataStr = response.parse().text();
            // 把JS中的加密算法用Java写一遍:
            String scode = dataStr.split("#")[0];
            String sxh = dataStr.split("#")[1];
            String code = username + "%%%" + password;
            String encoded = "";
            for (int i = 0; i < code.length(); i++) {
                if (i < 20) {
                    encoded = encoded + code.substring(i, i + 1)
                            + scode.substring(0, Integer.parseInt(sxh.substring(i, i + 1)));
                    scode = scode.substring(Integer.parseInt(sxh.substring(i, i + 1)), scode.length());
                } else {
                    encoded = encoded + code.substring(i, code.length());
                    i = code.length();
                }
            }
            return encoded;
        } catch (IOException e) {

        }
        return null;
    }

}
package cn.zyzpp.eduCookie;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class Util {
    /**
     * 将字节流转换成文件
     *
     * @param filename
     * @param data
     * @throws Exception
     */
    public static void saveFile(String filename, byte[] data) {

        if (data != null) {
            String filepath = filename;
            File file = new File(filepath);
            if (file.exists()) {
                file.delete();
            }
            try {
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(data, 0, data.length);
                fos.flush();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

后记

在模拟登陆该教务系统时,笔者观察到该教务系统还有一个不需要验证码即可登陆的网址:http://jwxt.qlu.edu.cn/jsxsd/xsxk/xklc_list,不过这个需要把用户名和密码通过JS算法进行前端加密合成为encoded字符串,如下

String encoded = playJs(username) + "%%%" + playJs(password);

然后直接带参POST即可。
具体的playJs()方法参考我的另一篇博客:Java执行JavaScript脚本破解encodeInp()加密


Java模拟登录带验证码的教务系统(原理详解)的更多相关文章

  1. php使用curl模拟登录带验证码的网站[开发篇]

    需求是这样的,需要登录带验证码的网站,获取数据,但是不可能人为一直去记录数据,想通过自动采集的方式进行,如下是试验出来的结果代码!有需要的可以参考下! <?php namespace Home\ ...

  2. php使用curl模拟登录带验证码的网站

    需求是这样的,需要登录带验证码的网站,获取数据,但是不可能人为一直去记录数据,想通过自动采集的方式进行,如下是试验出来的结果代码!有需要的可以参考下! <?php namespace Home\ ...

  3. 在Android上模拟登录广工正方教务系统查询成绩

    这是在博客园里开博以来写的第一篇博客. 因为之前看过很多人都有发过关于模拟登录正方软件获取数据的文章,自己觉得挺好玩的便也去动手一做,开始还以为挺难的,但实际做起来还蛮简单的,当然其中还有些小插曲. ...

  4. Python爬虫模拟登录带验证码网站

    问题分析: 1.爬取网站时经常会遇到需要登录的问题,这是就需要用到模拟登录的相关方法.python提供了强大的url库,想做到这个并不难.这里以登录学校教务系统为例,做一个简单的例子. 2.首先得明白 ...

  5. HttpURLConnection模拟登录学校的正方教务系统

    教务系统登录界面 如图1-1 1-1 F12-->network查看登录教务系统需要参数: __VIEWSTAT txtUserName TextBox2 txtSecretCode Radio ...

  6. Java面试必问通信框架NIO,原理详解

    NIO 流与块 通道与缓冲区 缓冲区状态变量 文件 NIO 实例 选择器 套接字 NIO 实例 内存映射文件 NIO与IO对比 Path Files NIO 新的输入/输出 (NIO) 库是在 JDK ...

  7. 【Java】【JVM】Sychronized底层加锁原理详解

    我们首先先看看JMM模型,话不多说,上图: JMM对应的8大原子操作: read(读取):从主内存读取数据 load(载入):将主内存读取到的数据写入工作内存 use(使用):从工作内存读取数据来计算 ...

  8. Java模拟登录系统抓取内容【转载】

    没有看考勤的习惯,导致我的一天班白上了,都是钱啊,系统也不发个邮件通知下....     为了避免以后还有类似状况特别写了个java模拟登录抓取考勤内容的方法(部分代码来自网络),希望有人修改后也可以 ...

  9. [PHP自动化-进阶]002.CURL模拟登录带有验证码的网站

    引言:继前文<模拟登录并采集数据>,大家似乎看不过瘾,这会再出一发,模拟实现带验证码网站的登录. 这篇文章主要介绍了PHP使用CURL实现对带有验证码的网站进行模拟登录的方法,可以帮助读者 ...

随机推荐

  1. 性能优化1--UI优化

    1.使用系统为我们提供了几个抽象的标签 ①include:重用 include中layout属性指定一个外部布局文件,通过该方式则不需要把这个布局文件在该代码中重复的写一遍了. 若include指定了 ...

  2. wap2app(十)--wap2app 添加原生底部导航,添加原生标题栏,填坑

    一.添加原生标题栏 添加原生标题栏可以参照 <wap2app(六)-- wap2app的原生标题头无法隐藏>,具体如下: 1.打开 sitemap.json文件 --> page配置 ...

  3. git 入门教程之本地和远程仓库的本质

    本地仓库和远程仓库在本质上没有太大区别,只不过一个是本地电脑,一个是远程电脑. 远程仓库不一定非得是 github 那种专门的"中央服务器",甚至局域网的另外一台电脑也可以充当&q ...

  4. springboot 学习之路 6(定时任务)

    目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...

  5. Solr5.5高级应用(基于tomcat9)

    一.配置solr 1.配置 注意:要是想放到其它路径下,可以修改此路径下的web.xml配置文件 修改内容如下: <!-- 将solrhome的绝对路径写入env-entry-value --& ...

  6. The server principal "sa" is not able to access the database "xxxx" under the current security context

    在SQL Server服务器上一个作业执行时,遇到下面错误信息: Message: Executed as user: dbo. The server principal "sa" ...

  7. MyBatis笔记----(2017年)最新的报错:Cannot find class [org.apache.commons.dbcp.BasicDataSource] for bean with name 'dataSource' defined in class path resource [com/ij34/mybatis/applicationContext.xml]; nested e

    四月 05, 2017 4:56:11 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRef ...

  8. hivesql优化的深入解析

    转载:https://www.csdn.net/article/2015-01-13/2823530 一个Hive查询生成多个Map Reduce Job,一个Map Reduce Job又有Map, ...

  9. python多线程与多进程--存活主机ping扫描以及爬取股票价格

    python多线程与多进程 多线程: 案例:扫描给定网络中存活的主机(通过ping来测试,有响应则说明主机存活) 普通版本: #扫描给定网络中存活的主机(通过ping来测试,有响应则说明主机存活)im ...

  10. 前端使用node.js+express+mockjs+mysql实现简单服务端,2种方式模拟数据返回

    今天,我教大家来搭建一个简单服务端 参考文章: https://www.jianshu.com/p/cb89d9ac635e https://www.cnblogs.com/jj-notes/p/66 ...