爬取正方教务管理系统获取学生信息

新版正方教务系统请点这里:模拟登陆新版正方教务管理系统(获取学籍信息、课表和成绩)

最近想学点爬虫玩玩,拿学校的教务系统练练手。学校与很多高校一样,用的是正方教务管理系统,非常的不好用,经常出现登陆不上去、卡死的情况,主页如下图所示:

主页

主页地址:http://222.24.62.120

模拟登录


1. 分析登录的URL和所需提供的数据

我们输入学号、密码和验证码登录后,点击登录。这时浏览器会向服务器提交一个POST请求:

登录请求

我们由上图中的数据可知,登录请求的URL地址为:

http://222.24.62.120/default2.aspx

所提交的数据除了学号、密码、验证码、用户类型,还有其他的数据:

  • __VIEWSTATE在源码中可以找到,是一个隐藏域,猜测是用来做验证
<input type="hidden" name="__VIEWSTATE" value="dDwxNTMxMDk5Mzc0Ozs+lYSKnsl/mKGQ7CKkWFJpv0btUa8=" />
  • Textbox1是上次登陆的用户学号
  • RadioButtonList1通过看源码可知为%D1%A7%C9%FA,是”学生”经过URL编码(gb2312)后的字符串。
  • 后四个为空可以不用管

创建一个类:ConnectJWGL
属性如下:

    private String stuNum;
    private String stuName;
    private String __VIEWSTATE = "";
    private Map<String,String> cookies = new HashMap<>();
    private Connection connection;
    private Connection.Response response;
    private Document document;

2. 获取Cookies和__VIEWSTATE

给主页发一个请求,然后将响应的Cookies保存下来。并在其中提取__VIEWSTATE的值。

在ConnectJWGL类中添加一个connectIndex方法
代码如下:

    //接获取cookies和__VIEWSTATE
    public void connectIndex(){
        try{
            //获取连接
            connection = Jsoup.connect("http://222.24.62.120");
            connection.header("User-Agent",// 配置模拟浏览器
                    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0");
            response = connection.timeout(3000).execute();
            //保存Cookies
            cookies = response.cookies();
            // 将响应转换为Dom树,以便获取__VIEWSTATE
            document = Jsoup.parse(response.body());
            for(Element element:document.getElementsByTag("input")) {
                if (element.attr("name").equals("__VIEWSTATE")) {
                    __VIEWSTATE = element.val();
                    break;
                }
            }
        }catch (IOException ex){
            ex.printStackTrace();
        }
    }

3. 取得验证码

在Chrome中定位验证码图片,代码如下

<img id="icode" title="看不清,换一张" onclick="reloadcode();" alt="看不清,换一张" src="CheckCode.aspx" border="0" style="POSITION: absolute; TOP: 5px; LEFT: 130px">

可以知道点击图片就会重新申请一个验证码,src为:

http://222.24.62.120/CheckCode.aspx

图片处理的方式有很多种,因为ORC图片识别成功概率低、机器学习学习难度比较大,所以采用把图片下载到本地再手动输入的方法,以后我倾向于自己写一个验证码识别工具。

在获取验证码的时候,要将Cookies上传,让服务器知道你的身份,要不然下载下来的图片没法用。

在ConnectJWGL类中添加一个downloadCheckcode方法
代码如下:

    //下载验证码到本地
    public void downloadCheckcode(){
        try{
            String captcha_url = "http://222.24.62.120/CheckCode.aspx";
            response = Jsoup.connect(captcha_url)
                    .cookies(cookies).ignoreContentType(true) // 获取图片需设置忽略内容类型
                    .userAgent("Mozilla").method(Connection.Method.GET).timeout(3000).execute();
            byte[] bytes = response.bodyAsBytes();

            //在本地建立文件夹
            File file = new File("/home/limeng/Desktop/checkcode.aspx");
            if (file.exists()) {
                file.delete();
            }
            OutputStream output = new FileOutputStream(file);
            BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);
            bufferedOutput.write(bytes);
            bufferedOutput.close();
            output.close();
        }catch (IOException ex){
            ex.printStackTrace();
        }
    }

4. 登录

在ConnectJWGL类中添加一个login方法

    //登录
    public boolean login(String stuNum,String password,String checkCode){
        this.stuNum = stuNum;
        stuName = "";

        //填充post数据
        Map<String, String> datas = new HashMap<>();
        datas.put("__VIEWSTATE",__VIEWSTATE);
        datas.put("txtUserName",stuNum);
        datas.put("TextBox2",password);
        datas.put("txtSecretCode",checkCode);
        datas.put("RadioButtonList1","%D1%A7%C9%FA");
        datas.put("Button1","");
        datas.put("lbLanguage","");
        datas.put("hidPdrs","");
        datas.put("hidsc","");

        try{
            connection = Jsoup.connect("http://222.24.62.120/default2.aspx");
            connection.header("User-Agent",
                    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0");
            // 设置cookie和post上面的map数据
            response = connection.postDataCharset("GB2312").ignoreContentType(true).method(Connection.Method.POST)
                    .data(datas).cookies(cookies).execute();
            document = response.parse();

            if(document.title().equals("欢迎使用正方教务管理系统!请登录")){
                String error = document.getElementsByTag("script").get(1).data();
                Pattern pattern = Pattern.compile("(?<=alert\\(')[^']*");
                Matcher matcher = pattern.matcher(error);
                while(matcher.find()){
                    System.out.print("登陆失败,");
                    System.out.println(matcher.group());
                }
                return false;
            }else {
                stuName = document.getElementById("xhxm").text();
                stuName = stuName.substring(0,stuName.length()-2);
                System.out.println("登陆成功,欢迎你"+stuName+"!");
                return true;
            }
        }catch (IOException ex){
            ex.printStackTrace();
            return false;
        }
    }

登录成功会跳转到:

http://222.24.62.120/xs_main.aspx?xh=学号

否则转到登录界面,并提示错误信息。

获取学生个人信息


在登录成功后,我们点击信息维护中的(个人信息)。

这里写图片描述

这时会去以get方式请求:

http://222.24.62.120/xsgrxx.aspx

传递了三个参数:

  • xh:学号
  • xm:URL编码过的姓名
  • gnmkdm:N121501(应该是业务编号,请求课表就是N121603)

我们不知道学生的姓名,但是通过查看主界面,可以发现“欢迎您: ××同学”,简单处理一下即可。

Referer(很重要,要不然无法请求上面的连接

http://222.24.62.120/xs_main.aspx?xh=学号 

在ConnectJWGL类中添加一个getStudentInformation方法
代码如下:

    //获取学生个人信息
    public void getStudentInformation(){
        try{
            String infoURL = "http://222.24.62.120/xsgrxx.aspx?xh="+stuNum+"&xm="+URLEncoder.encode(stuName,"GB2312")+"&gnmkdm=N121501";
            connection = Jsoup.connect(infoURL);
            response = connection.ignoreContentType(true).method(Connection.Method.GET)
                            .userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0")
                            .referrer("http://222.24.62.120/xs_main.aspx?xh="+stuNum)
                            .cookies(cookies).postDataCharset("GB2312").timeout(3000).execute();
            document = response.parse();
            if(document.getElementById("lbxsgrxx_xb") != null){
                System.out.println("---基本信息---");
                System.out.println(document.getElementById("lbxsgrxx_xb").text()+document.getElementById("lbl_xb").text());
                System.out.println(document.getElementById("lbxsgrxx_csrq").text()+document.getElementById("lbl_csrq").text());
                System.out.println(document.getElementById("lbxsgrxx_xy").text()+document.getElementById("lbl_xy").text());
                System.out.println(document.getElementById("lbxsgrxx_dqszj").text()+document.getElementById("lbl_dqszj").text());
                System.out.println(document.getElementById("TDzymc").text()+document.getElementById("lbl_zymc").text());
                System.out.println(document.getElementById("lbxsgrxx_xzb").text()+document.getElementById("lbl_xzb").text());
            }else {
                System.out.println("获取信息失败");
            }
        }catch (IOException ex){
            ex.printStackTrace();
        }
    }

测试


Main.java

import java.util.Scanner;

public class Main {
    public static void main(String[] args){
        String stuNum;
        String password;
        String checkCode;

        Scanner input = new Scanner(System.in);
        ConnectJWGL connectJWGL = new ConnectJWGL();
        connectJWGL.downloadCheckcode();
        System.out.print("请输入学号:");
        stuNum = input.next();
        System.out.print("请输入密码:");
        password = input.next();
        System.out.print("请输入验证码:");
        checkCode = input.next();
        if(connectJWGL.login(stuNum,password,checkCode)){
            connectJWGL.getStudentInformation();
        }
        input.close();
    }
}

测试

完整代码点这里:爬取学校教务系统获取学生信息

要注意的细节

  1. 在获取Cookies后,以后的每一次请求都要把Cookies带上。
  2. Too many redirects occurred trying to load URL 表示进入重定向循环,不知道该跳转到哪一个界面。如果把自动跳转关闭就出现页面提示:Object moved to here.
    这个问题是在获取个人信息时出现的,由于在登录成功时不小心更新了一次Cookies,导致Cookies为空,请求时服务器不知道我的身份,修正后就可以正常获取信息了。
  3. 请求时要注意目标请求是否需要Referer。Referer告诉服务器我是从哪个页面链接过来的,服务器基此可以获得一些信息用于处理,有网页会限定请求的上一个地址。
参考

Jsoup Cookbook(中文版)
Java爬虫初识之模拟登录
Java爬虫教程:模拟用户表单登录

猜你喜欢

转载自blog.csdn.net/ldx19980108/article/details/81217899