Java模拟校园网登陆

Posted by lvyonghao on November 15, 2019

Java爬虫登陆校园网

  • 分享一次我的Java爬虫经历,在这一次爬虫过程中学到很多,拿出来和大家分享
  • 阅读本文的前置学习条件:
    • Java基本语法
    • Maven
    • Http协议有一定的了解(尤其是POST GET请求)
    • HTML的基本结构逻辑
    • 浏览器的开发者工具
  • 本文大概阅读时间 : 10 min ~ 15 min

1.准备工作

首先我们使用Java的IDEA集成开发环境,并使用一个Maven项目作为项目的包管理器。

其次需要导入几个Jar包,这次爬虫需要的是httpclient,commons-io,tess4j

因为如果要对数据进行处理,我还添加以下Jar包:junit,fastjson,jsoup

  • httpclient : HttpClient 是Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

    Maven依赖:

    <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.5.10</version>
            </dependency>
    
  • commons-io : Apache的一些工具集,在我们文件IO上用得到

    <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.5</version>
    </dependency>
    
  • tess4j :用来做ORC光学识别,用来应对一些简单的验证码

    <!-- https://mvnrepository.com/artifact/net.sourceforge.tess4j/tess4j -->
            <dependency>
                <groupId>net.sourceforge.tess4j</groupId>
                <artifactId>tess4j</artifactId>
                <version>4.4.1</version>
            </dependency>
    
  • junit : JUnit是一个Java语言的单元测试框架。用来做测试,可以不添加到项目当中。

    <!-- https://mvnrepository.com/artifact/junit/junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
    
  • fastjson : 阿里开发的最快的json处理工具,在对数据进行实体化,存入数据库用到。

    <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.62</version>
    </dependency>
    
  • Jsoup : 是一款Java的HTML解析器,主要用来对HTML解析。本篇不会用得到,读者酌情添加(迟早得用是不是哈哈)

    <dependency>
                <groupId>org.jsoup</groupId>
                <artifactId>jsoup</artifactId>
                <version>1.10.3</version>
    </dependency>
    

2.网站分析

对于初学者来说如何对你所需要的爬取的网页进行分析可能是最困难的一步

初学者往往通过一些基础的学习,不论是Python,或者是Java,感觉自己可以了,实际操作当中,突然发现你想要的网站比你学习时候的网站复杂了很多,造成了很多新手的劝退,想要搞好爬虫,HTTP协议,前后端只是还是非常重要的

话不多说,让我们一起来用Chorm的开发者工具去分析一下这个校园网

  • 我们的校园网需要通过VPN进行登陆所以URL上面可能和平时大家看到的不一样

  • 首先我们观察整个校园网的网页

    MwBZb4.md.png

    通过开发者工具我们很清楚的看到了校园网的登陆通过表单,使用POST方式提交数据,我们通过输入相应的信息我们再去分析网页的请求

  • 我们先清空Network,输入信息跑一下

    MwDgOO.png

    我们在NetWork的Doc当中可以发现有一个loginAction.do,这个从名字上来看应该是关于我们登陆的信息,点开我们看一下他的Header:

    • Status Code: 200 说明我们请求成功了
    • Request Method: POST 请求方式POST说明是我们提交的表单服务器返回的请求
    • Form Date :分为三个字段,zjh 是学号,mm 是密码,v_yzm 是验证码,这一部分就是爬虫当中最关键的部分
  • 由上述的情况我们可以知道,我们想要登陆校园网需要向http://202.207.247.44:8065/loginAction.do发送一个POST请求,请求的内容为学号,密码,验证码,服务器就会给我们返回我们登陆的页面

  • 就此我们对于网站的分析就到此结束了,接下来我们进入代码阶段


3.代码实现

  • 项目的目录层次结构为:分为三个包,Dao存放实体,HttpTool存放我们的HttpClient工具,Tess4j中存放我们关于光学识别的工具

  • 在Dao中写入我们的实体类

    public class User {
        private String username;
        private String password;
        public User(){};
        public User(String username,String password){
            this.password = password;
            this.username = username;
        }
      
        public String getUsername() {
            return username;
        }
      
        public void setUsername(String username) {
            this.username = username;
        }
      
        public String getPassword() {
            return password;
        }
      
        public void setPassword(String password) {
            this.password = password;
        }
      
        @Override
        public String toString() {
            return "[" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    ']';
        }
    }
    
  • Tess4j中写一个工具Tess4JTool

    我们只需要给入FIle,返回一个String,做一个最简单光学识别,当然关于ORC的识别包,需要大家自己的搜素。

    public class Tess4JTool {
        //使用英文字库 - 识别图片
        public static String testEn(File imageFile) throws Exception {
      
            BufferedImage image = ImageIO.read(imageFile);
            //对图片进行处理
            image = convertImage(image);
            ITesseract instance = new Tesseract();//JNA Interface Mapping
            instance.setDatapath("/usr/local/Cellar/tesseract/4.1.0/share/tessdata");
            String result = instance.doOCR(image); //识别
            return result;
        }
      
        //使用中文字库 - 识别图片
        public static String testZh(File imageFile) throws Exception {
            BufferedImage image = ImageIO.read(imageFile);
            //对图片进行处理
            //image = convertImage(image);
            ITesseract instance = new Tesseract();//JNA Interface Mapping
            instance.setLanguage("chi_sim");//使用中文字库
            instance.setDatapath("/usr/local/Cellar/tesseract/4.1.0/share/tessdata");
            String result = instance.doOCR(image); //识别
            return result;
        }
      
        //对图片进行处理 - 提高识别度
        public static BufferedImage convertImage(BufferedImage image) throws Exception {
            //按指定宽高创建一个图像副本
            //image = ImageHelper.getSubImage(image, 0, 0, image.getWidth(), image.getHeight());
            //图像转换成灰度的简单方法 - 黑白处理
            image = ImageHelper.convertImageToGrayscale(image);
            //图像缩放 - 放大n倍图像
            image = ImageHelper.getScaledInstance(image, image.getWidth() * 3, image.getHeight() * 3);
            return image;
        }
    }
    
  • HttpTool :Yanzhengimage。通过图片存储位置获取验证码

    public class Yanzhengimage {
      
        //通过ORC获取验证码
        public static String GetYZM(String imagePath) throws Exception {
            String YZM = "";
            File file = new File(imagePath);
            YZM = Tess4JTool.testEn(file);
            return YZM;
        }
    }
    
  • HttpTool : clinet 我们用一个类去整合刚才各个类的方法,并用login方法聚合之前的方法

    public class Client {
        private User user;
        HttpClient client = HttpClients.createDefault();
        HttpResponse response = null;
        String rawHtml;
      
        public Client(User user)
        {
            this.user = user;
        }
      
        public void login()
        {
            HttpGet getLogin = new HttpGet("http://202.207.247.44:8065/loginAction.do");
      
            try {
                //获得Get请求
                client.execute(getLogin);
                //获取验证码
                String code = "";
                code = getVerifyCode(client);					//获取验证码字符
                code = code.substring(0,code.length() - 1);		//去掉末尾的字符
                System.out.print(code);
      
                //设定POST请求参数
                ArrayList<NameValuePair> params = new ArrayList<>();
                params.add(new BasicNameValuePair("zjh",user.getUsername()));
                params.add(new BasicNameValuePair("mm",user.getPassword()));
                params.add(new BasicNameValuePair("v_yzm",code));
      
                HttpPost post = new HttpPost("http://202.207.247.44:8065/loginAction.do");
                post.setEntity(new UrlEncodedFormEntity(params));       //捆绑参数
                response = client.execute(post);                        //登陆
                rawHtml = EntityUtils.toString(response.getEntity(),"UTF-8");   //返回响应内容转为字符串
                System.out.println(rawHtml);
            } catch (ClientProtocolException e) {
                System.out.println(e.getMessage());
            } catch (IOException e) {
                System.out.println(e.getMessage());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
      
        public String getVerifyCode(HttpClient client)
        {
            String YZM = "";
            HttpGet getCode = new HttpGet("http://202.207.247.44:8065/validateCodeAction.do");
            HttpResponse response;
            try{
                response = client.execute(getCode);
                HttpEntity entity = response.getEntity();
                InputStream inputStream = entity.getContent();
                File image = new File("verifyCode.jpeg");
                FileUtils.copyToFile(inputStream,image);
                YZM = Tess4JTool.testEn(image);
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return YZM;
        }
    }
    
  • 最后我们通过HttpClientTest尝试一下

  public class HttpClientToolTest {
      public static void main(String[] args) throws IOException {
          User user = new User("2017006353","255532");;
          Client client = new Client(user);
          client.login();
      }
  }

控制台输出内容:

<html>
<head>
<title>学分制综合教务</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<frameset rows="48,*" frameborder="NO" border="0" framespacing="0">

   <frame src="/menu/s_top.jsp" name="topFrame" scrolling="NO" noresize frameborder="NO" border="0" framespacing="0">
 
  <frame src="/menu/mainFrame.jsp" name="bottomFrame" scrolling="Auto" frameborder="NO" border="0" framespacing="0">
</frameset>

<noframes><body>
</body></noframes>
</html>

说明我们登陆成功了!!!需要其他的内容就需要借助Jsoup来进行解析了,限于文章篇幅我就不在此说了,放到下一篇博客当中。