用java模拟登录正方教务系统,抓取课表和个人成绩等数据

本文介绍如何使用Java和httpClient库爬取学校教务系统的课表信息,包括登录验证、维持登录状态、抓取课表数据及解析HTML。

一、第三方工具

         这里我用到了httpClient这个第三方包,相信很多人都认识这个包,不认识的话可以自行百度一下,httpClient和传统的URLConnection相比,更加强大,更加灵活,更加易用,我用的是httpcomponents-client-4.5.2,下载地址:http://hc.apache.org/downloads.cgi


二、思路描述

        这里就拿获取课表的例子说一下,首先,要登录教务系统,就要获取登录的验证码,然后输入学号密码和验证码后,向教务网发起登录请求,接着要做的就是维持登录状态,登录状态是靠cookie里的sessionID这个参数维持的,只需要保存cookie就行了,在后续的所有提交的请求里,只要都带着cookie一起提交,就能保持在登录状态,保证获取正确的页面,在登录成功后,就在响应页面里找到查询个人课表的链接,然后再提交查询课表的请求,得到的响应就是个人课表的页面,这时就直接抓取课表部分的内容就行了。至于怎么准确抓取相应的数据,当然是用正则表达式了,不懂正则表达式的自行百度。


三、页面分析

        按F12打开浏览器的开发者工具(我用的是火狐浏览器),然后访问学校的正方教务网,点击页面上的登录按钮后,开发者工具窗口中可以看到如下图片中的内容
图片
        可以看到点击登录按钮后浏览器提交了一个post请求,请求/default2.aspx这个页面,然后表单数据里有若干个参数,包括学号、密码、验证码等,这里面还有一个__VIEWSTATE参数,查看页面源码得知这是一个表单隐藏域,这个参数的值要每次都在相应页面中通过正则匹配抽取出来。如果登录成功的话,会重定向到页面/xs_main.aspx?xh=***,这里的"***"就是对应的学生学号。
        接下来点击个人课表的链接,在开发者工具中可以看到请求课表页面的链接和对应参数,这些参数的值都可以在响应的HTML中匹配出来。

        最后,在个人课表的页面HTML中,我们能看到所有的课程信息,利用正则匹配我们就能把每个课程的名称、上课时间、上课教室、任课老师等信息抽取出来,并封装成一个java对象。

四、代码实现

        在这之前,我把一些固定的链接等字符串封装到一个常量类里,代码如下
/** 
 * 常量类 
 * @author EsauLu 
 * 
 */  
public class Constant {  
  
    /** 
     * 验证码为空 
     */  
    public static final String CHECK_NULL_ERROR="验证码不能为空,如看不清请刷新!!";  
      
    /** 
     * 验证码不正确 
     */  
    public static final String CHECK_ERROR="验证码不正确!!";  
      
    /** 
     * 密码错误 
     */  
    public static final String PASSWD_ERROR="密码错误!!";  
      
    /** 
     * 字符编码 
     */  
    public static final String ENCODING="GB2312";  
      
    /** 
     * 用户类型 
     */  
    public static final String RADIO_BUTTON_LIST="学生";  
      
      
    /** 
     * 教务网地址 
     */  
    public static final String BASE_URL="http://jw.jluzh.com";  
      
    /** 
     * 验证码URL 
     */  
    public static final String CHECK_IMAGE_URL=BASE_URL+"/CheckCode.aspx";  
      
    /** 
     * 登陆URL 
     */  
    public static final String LOGIN_URL=BASE_URL+"/default2.aspx";  
      
    /** 
     * 登陆后主页面URL 
     */  
    public static final String STUDENT_URL=BASE_URL+"/xs_main.aspx?xh=";  
      
}  


[java]  view plain  copy



        首先,我定义了一个HttpInterface接口,定义了一些用于登录、获取验证码、获取课表等等的方法,详细请看代码
import org.apache.http.client.entity.UrlEncodedFormEntity;  
import com.jluzh.jw.bean.CourseTable;  
import com.jluzh.jw.bean.PersonalInfo;  
import com.jluzh.jw.bean.User;  
  
/** 
 * 获取数据的接口 
 * @author EsauLu 
 * 
 */  
public interface HttpInterface {      
  
    /** 
     * 初始化,主要用于收集cookie和viewState 
     */  
    public void init();  
      
    /** 
     * 根据指定url发送给请求 
     * @param url 请求url 
     * @param ref 引用 
     * @return 响应页面的HTML文档 
     */  
    public StringBuffer sendGetRequest(String url,String ref);  
      
    /** 
     * 根据指定url和参数值发送post请求 
     * @param url 请求url 
     * @param ref 引用 
     * @param entity 参数列表 
     * @return 响应页面的HTML文档 
     */  
    public StringBuffer sendPostRequest(String url,String ref, UrlEncodedFormEntity entity);  
      
    /** 
     * 获取验证码 
     * @return 验证码图片 
     */  
    public byte[] getCheckImg();  
      
    /** 
     * 登陆 
     * @param user 用户信息 
     * @return 返回登陆是否成功 
     */  
    public boolean login(User user);  
      
    /** 
     * 根据学年度和学期获取课表 
     * @param xnd 学年度 
     * @param xqd 学期 
     * @return 课表 
     */  
    public CourseTable getCourseTable(String xnd,String xqd);  
      
    /** 
     * 根据学年度和学期获取课表的Json串 
     * @param xnd 学年度 
     * @param xqd 学期 
     * @return 课表Json串 
     */  
    public String getCourseTableAsJson(String xnd,String xqd);  
      
    /** 
     * 获取个人信息 
     * @param url 查询个人信息的url 
     * @return 个人信息 
     */  
    public PersonalInfo getPersonalInfo(String url);  
      
    /** 
     * 获取错误信息 
     * @return 返回错误信息 
     */  
    public String getErrorMessege();  
  
}  
  
        然后下面就是接口的实现。需要说明一下的是,HttpService这个实现类做了维持登录的工作,就是把cookie保存起来。在初始化时,init()函数里首先访问一下教务网,然后记录cookie,cookie里有个参数ASP.NET_SessionId的参数,维持登录靠的就是这个参数。然后在获取验证码、登录、获取课表等的函数实现里,提交的请求都要设置cookie域,否则的话响应内容将是登录页面(这个知道web后端开发的都懂吧)。
co
import java.io.IOException;  
import java.io.InputStream;  
import java.io.UnsupportedEncodingException;  
import java.util.ArrayList;  
import java.util.regex.Matcher;  
import java.util.regex.Pattern;  
  
import org.apache.http.client.ClientProtocolException;  
import org.apache.http.client.entity.UrlEncodedFormEntity;  
import org.apache.http.client.methods.CloseableHttpResponse;  
import org.apache.http.client.methods.HttpGet;  
import org.apache.http.client.methods.HttpPost;  
import org.apache.http.impl.client.CloseableHttpClient;  
import org.apache.http.impl.client.HttpClients;  
import org.apache.http.message.BasicNameValuePair;  
import org.apache.http.util.EntityUtils;  
  
import com.jluzh.jw.bean.Course;  
import com.jluzh.jw.bean.CourseTable;  
import com.jluzh.jw.bean.PersonalInfo;  
import com.jluzh.jw.bean.StuSimpleInfo;  
import com.jluzh.jw.bean.User;  
import com.jluzh.jw.constant.Constant;  
import com.jluzh.jw.tool.HtmlTools;  
  
public class HttpService implements HttpInterface {  
      
    /** 
     * Http客户端 
     */  
    private CloseableHttpClient mHttpClient;  
  
    /** 
     * 记录cookie 
     */  
    private String mCookie;  
  
    /** 
     * 记录正方教务系统页面表单的__VIEWSTATE的值 
     */  
    private String mViewState;  
  
    /** 
     * 已登陆用户的信息 
     */  
    private User mUser;  
      
    /** 
     * 登陆错误信息 
     */  
    private String mErrorMessege;  
  
    /** 
     * 查询课程表信息的URL 
     */  
    private String mCourseURL;  
      
    /** 
     * 查询个人信息的URL 
     */  
    private String mPersonalInfoURL;  
      
    /** 
     * 查询成绩表的URL 
     */  
    private String mScorceURL;  
      
    /** 
     * 构造函数 
     */  
    public HttpService() {  
        // TODO Auto-generated constructor stub  
        this.mErrorMessege="no error";  
        mHttpClient=HttpClients.createDefault();  
        init();  
    }  
      
    @Override  
    public void init() {  
        // TODO Auto-generated method stub  
        String url=Constant.BASE_URL;  
        try {  
              
            HttpGet httpGet=new HttpGet(url);  
            CloseableHttpResponse response=mHttpClient.execute(httpGet);//提交请求获得响应  
            mCookie=response.getFirstHeader("Set-Cookie").getValue();   //获取cookie  
            StringBuffer sb=sendGetRequest(url,null);   //发送访问请求并获得响应页面  
            mViewState=HtmlTools.findViewState(sb.toString()); //提取页面表单中的__VIEWSTATE的值  
              
        } catch (ClientProtocolException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        } catch (IOException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
          
    }  
      
    @Override  
    public StringBuffer sendGetRequest(String url,String ref) {  
        // TODO Auto-generated method stub  
          
        StringBuffer sb=new StringBuffer();  
        InputStream in=null;  
          
        try {             
  
            HttpGet httpGet=new HttpGet(url);  
            httpGet.setHeader("Cookie", mCookie);//设置cookie           
            if(ref!=null&&!ref.equals("")){  
                httpGet.setHeader("Referer",ref);//如果有地址引用则设置  
            }  
            CloseableHttpResponse response=mHttpClient.execute(httpGet);//提交请求获得响应  
            in=response.getEntity().getContent();  
              
            //获取响应内容  
            if(in!=null){  
                int len=-1;  
                byte[] data=new byte[1024];  
                while((len=in.read(data))!=-1){  
                    String s=new String(data,0,len,Constant.ENCODING);  
                    sb.append(s);  
                }  
            }  
              
              
        } catch (Exception e) {  
            // TODO: handle exception  
        }finally{  
            try {  
                if(in!=null){  
                    in.close();  
                }  
            } catch (Exception e2) {  
                // TODO: handle exception  
            }  
        }  
          
        return sb;  
    }  
      
    @Override  
    public StringBuffer sendPostRequest(String url, String ref, UrlEncodedFormEntity entity) {  
        // TODO Auto-generated method stub  
        StringBuffer sb=new StringBuffer();  
        HttpPost httpPost=new HttpPost(url);  
        InputStream in=null;          
        try {  
            httpPost.setHeader("Cookie", mCookie);  //设置cookie    
            if(ref!=null&&!ref.equals("")){  
                httpPost.setHeader("Referer",ref);//如果有地址引用则设置  
            }  
            httpPost.setEntity(entity);//设置请求参数  
            CloseableHttpResponse response=mHttpClient.execute(httpPost);//提交请求  
            in=response.getEntity().getContent();//获得响应流对象  
              
            //获取响应内容  
            int len=-1;  
            byte[] data=new byte[1024];  
            while((len=in.read(data))!=-1){  
                String s=new String(data,0,len,Constant.ENCODING);  
                sb.append(s);  
            }  
        } catch (Exception e) {  
            // TODO: handle exception  
        }finally{  
            try {  
                if(in!=null){  
                    in.close();  
                }  
            } catch (Exception e2) {  
                // TODO: handle exception  
            }  
        }     
        return sb;  
    }  
      
    @Override  
    public byte[] getCheckImg() {  
        // TODO Auto-generated method stub  
          
        String url=Constant.CHECK_IMAGE_URL;  
        HttpGet httpGet=new HttpGet(url);  
        byte[] imgByte=null;  
          
        try {  
              
            CloseableHttpResponse response=mHttpClient.execute(httpGet);  
            imgByte=EntityUtils.toByteArray(response.getEntity());  
              
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
          
        return imgByte;  
    }  
  
    @Override  
    public boolean login(User user) {  
        // TODO Auto-generated method stub  
  
        //组织登陆请求参数  
        ArrayList<BasicNameValuePair> params=new ArrayList<BasicNameValuePair>();  
        params.add(new BasicNameValuePair("__VIEWSTATE", mViewState));//__VIEWSTATE,不可缺少这个参数  
        params.add(new BasicNameValuePair("txtUserName", user.getName()));//学号  
        params.add(new BasicNameValuePair("TextBox2", user.getPasswd()));//密码  
        params.add(new BasicNameValuePair("txtSecretCode",user.getCheck()));//验证码  
        params.add(new BasicNameValuePair("RadioButtonList1", Constant.RADIO_BUTTON_LIST));//登陆用户类型  
        params.add(new BasicNameValuePair("Button1", ""));  
        params.add(new BasicNameValuePair("lbLanguage", ""));  
        params.add(new BasicNameValuePair("hidPdrs", ""));  
        params.add(new BasicNameValuePair("hidsc", ""));  
          
        try {  
            UrlEncodedFormEntity entity=new UrlEncodedFormEntity(params,Constant.ENCODING); //封装成参数对象     
            StringBuffer sb=sendPostRequest(Constant.LOGIN_URL,null, entity);//发送请求  
            mUser=user;//记录登陆的用户  
            String html=sb.toString();  
              
            //检测是否有登陆错误的信息,有则记录信息,否则登陆成功  
            if(html.contains(Constant.CHECK_ERROR)){  
                mErrorMessege=Constant.CHECK_ERROR;  
            }else if(html.contains(Constant.CHECK_NULL_ERROR)){  
                mErrorMessege=Constant.CHECK_NULL_ERROR;  
            }else if(html.contains(Constant.PASSWD_ERROR)){  
                mErrorMessege=Constant.PASSWD_ERROR;  
            }else{    
                //登陆成功,重定向获取主页面  
                StringBuffer userHtml=sendGetRequest(Constant.STUDENT_URL+user.getName(),null);  
                saveQueryURL(userHtml.toString());  //根据响应内容找到并保存查询各种信息的URL   
                return true;//返回登陆成功  
            }  
        } catch (UnsupportedEncodingException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
          
        return false;  
    }  
  
    @Override  
    public CourseTable getCourseTable(String xnd,String xqd) {  
        // TODO Auto-generated method stub  
        String url=Constant.BASE_URL+mCourseURL;//查询课表的URL  
        String referer=Constant.STUDENT_URL+mUser.getName();//引用地址  
        StringBuffer courseHtml=null;  
        CourseTable couresTable=new CourseTable();  
          
        try {  
            //没有学年度和学期的的信息,则发送get请求,否则发送post请求  
            if(xnd==null||xqd==null){  
                courseHtml=sendGetRequest(url, referer);  
            }else{  
                //记录post参数后发送请求  
                ArrayList<BasicNameValuePair> params=new ArrayList<BasicNameValuePair>();  
                params.add(new BasicNameValuePair("__EVENTTARGET", "xqd"));  
                params.add(new BasicNameValuePair("__EVENTARGUMENT", ""));  
                params.add(new BasicNameValuePair("__VIEWSTATE", mViewState));  
                params.add(new BasicNameValuePair("xnd", xnd));  
                params.add(new BasicNameValuePair("xqd", xqd));  
                UrlEncodedFormEntity entity=new UrlEncodedFormEntity(params,Constant.ENCODING);  
                courseHtml=sendPostRequest(url, referer, entity);  
            }  
              
            String html=courseHtml.toString();  //响应HTML文档    
            mViewState=HtmlTools.findViewState(html);//记录__VIEWSTATE  
              
            StuSimpleInfo stuInfo=HtmlTools.getStuInfo(html);  
            String[] xnds=HtmlTools.getXnd(html);   //在响应内容中获取学年度选项列表     
            String[] xqds=HtmlTools.getXqd(html);   //在响应内容中获取学期选项列表      
            ArrayList<Course> courses=HtmlTools.getCourseList(html);  //在响应内容中获取课表  
              
            //如果传进来的学年度和学期参数为空,则使用默认选项  
            if(xnd==null&&xnds.length>0) xnd=xnds[0];      
            if(xqd==null&&xqds.length>0) xqd=xqds[0];  
              
            //保存获取到的所有信息  
            couresTable.setXnd(xnds);  
            couresTable.setXqd(xqds);  
            couresTable.setCurrXnd(xnd);  
            couresTable.setCurrXqd(xqd);                  
            couresTable.setCourses(courses);  
            couresTable.setSimpleInfo(stuInfo);  
              
        } catch (UnsupportedEncodingException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
          
        return couresTable;  
    }  
      
    @Override  
    public String getCourseTableAsJson(String xnd, String xqd) {  
        // TODO Auto-generated method stub  
          
        CourseTable courseTable=getCourseTable(xnd, xqd);  
        StringBuffer sb=new StringBuffer();  
          
        sb.append("{");  
        for(Course c:courseTable.getCourses()){  
            sb.append("\n\t{");  
            sb.append("\n\t\t\"name\":\""+c.getName()+"\"");  
            sb.append("\n\t\t\"classRoom\":\""+c.getClassRoom()+"\"");  
            sb.append("\n\t\t\"teacher\":\""+c.getTeacher()+"\"");  
            sb.append("\n\t\t\"classTime\":\""+c.getClassTime()+"\"");  
            sb.append("\n\t\t\"weekNum\":\""+c.getWeekNum()+"\"");  
            sb.append("\n\t\t\"startWeek\":\""+c.getStartWeek()+"\"");  
            sb.append("\n\t\t\"endWeek\":\""+c.getEndWeek()+"\"");  
            sb.append("\n\t\t\"weekState\":\""+c.getWeekState()+"\"");  
            sb.append("\n\t\t\"number\":\""+c.getNumber()+"\"");  
            sb.append("\n\t\t\"day\":\""+c.getDay()+"\"");                    
            sb.append("\n\t}\n");  
        }  
        sb.append("}");  
          
        return sb.toString();  
    }  
  
    @Override  
    public PersonalInfo getPersonalInfo(String url) {  
        // TODO Auto-generated method stub  
        return null;  
    }  
  
      
    @Override  
    public String getErrorMessege() {  
        // TODO Auto-generated method stub  
        return mErrorMessege;  
    }  
  
    /** 
     * 查找并保存查询各种信息的URL 
     * @param html HTML文档 
     */  
    private void saveQueryURL(String html) {  
        // TODO Auto-generated method stub        
  
        String pattern="<a href=\"(\\w+)\\.aspx\\?xh=(\\d+)&xm=(.+?)&gnmkdm=N(\\d+)\" target='zhuti' onclick=\"GetMc\\('(.+?)'\\);\">(.+?)</a>";  
        Pattern p=Pattern.compile(pattern);  
        Matcher m=p.matcher(html);  
          
        while(m.find()){  
            String res=m.group();  
            String url=res.substring(res.indexOf("href=\"")+6);  
            url=url.substring(0,url.indexOf("\""));  
            url="/"+url;  
              
            if(res.contains("学生个人课表")){  
                mCourseURL=url;  
                continue;  
            }  
            if(res.contains("成绩查询")){  
                mScorceURL=url;  
                continue;  
            }  
            if(res.contains("个人信息")){  
                mPersonalInfoURL=url;  
            }  
        }  
          
    }  
      
      
    public User getmUser() {  
        return mUser;  
    }  
      
} 

        上面的HttpService里用到一个HtmlTools类,这个类里包含了一些了的静态方法,是专门用来解析响应页面的HTML里面的信息的,代码如下
import java.util.ArrayList;  
import java.util.regex.Matcher;  
import java.util.regex.Pattern;  
  
import com.jluzh.jw.bean.Course;  
import com.jluzh.jw.bean.StuSimpleInfo;  
import com.jluzh.jw.factor.BeanFactor;  
  
/** 
 * HTML工具类,主要用于提取HTML文档中的信息 
 * @author EsauLu 
 * 
 */  
public class HtmlTools {  
  
    private static final int FIND_XND=1;//学年度  
    private static final int FIND_XQD=2;//学期  
      
    /** 
     * 查找__VIEWSTATE参数的值 
     * @param html HTML文档 
     * @return 返回 
     */  
    public static String findViewState(String html) {  
        String res="";  
        String pattern="<input type=\"hidden\" name=\"__VIEWSTATE\" value=\"(.*?)\" />";  
          
        Pattern p=Pattern.compile(pattern);  
        Matcher m=p.matcher(html);  
          
        if(m.find()){  
            res=m.group();  
            res=res.substring(res.indexOf("value=\"")+7,res.lastIndexOf("\""));  
        }  
        return res;  
    }  
      
    /** 
     * 查找课表部分的HTML字符串 
     * @param html HTML文档 
     * @return 课表的HTML串 
     */  
    private static String findCourseTableHtml(String html){  
        String res="";  
        String tar="<table id=\"Table1\" class=\"blacktab\" bordercolor=\"Black\" border=\"0\" width=\"100%\">";  
        String pattern="<table id=\"Table1\" class=\"blacktab\" bordercolor=\"Black\" border=\"0\" width=\"100%\">([\\S\\s]+?)</table>";          
        Pattern p=Pattern.compile(pattern);  
        Matcher m=p.matcher(html);        
        if(m.find()){  
            res=m.group(0);  
            res=res.substring(res.indexOf(tar)+tar.length(),res.lastIndexOf("</table>")).trim();  
        }else{  
            System.out.println(html);  
            System.out.println("什么都没有");  
        }  
        return res;  
    }  
      
    /** 
     * 在HTML中提取学年度或者学期的选项的HTML记录串 
     * @param html HTML文档 
     * @param x 代表学期或者学年度的参数 
     * @return  返回HTML表示的学年度或者学期选项 
     */  
    private static String findXndOrXqdHtml(String html,int x){  
        String res="";  
        String pattern=null;  
        switch(x){  
            case FIND_XND:  
                pattern="<select name=\"xnd\" onchange=\"__doPostBack\\('xnd',''\\)\" language=\"javascript\" id=\"xnd\">([\\s\\S]+?)</select>";  
                break;  
            case FIND_XQD:  
                pattern="<select name=\"xqd\" onchange=\"__doPostBack\\('xqd',''\\)\" language=\"javascript\" id=\"xqd\">([\\s\\S]+?)</select>";  
                break;  
        }  
        Pattern p=Pattern.compile(pattern);  
        Matcher m=p.matcher(html);        
        if(m.find()){  
            res=m.group(1);  
        }  
        return res.trim();  
    }  
      
    /** 
     * 在HTML中提取学年度或者学期的选项列表 
     * @param html HTML文档 
     * @param x 代表学年度或者学期 
     * @return 返回学年度或者学期的选项数组 
     */  
    private static String[] getOptions(String html,int x){  
      
        String[] ops=null;  
        String res="";  
        String tar=findXndOrXqdHtml(html, x);  
        ArrayList<String> arr=new ArrayList<String>();  
        String pattern="<option([\\s\\S]*?)>(.*?)</option>";          
        Pattern p=Pattern.compile(pattern);  
        Matcher m=p.matcher(tar);         
        while(m.find()){  
            res=m.group(2);  
            arr.add(res);  
        }  
          
        ops=new String[arr.size()];  
        for(int i=0;i<ops.length;i++){  
            ops[i]=arr.get(i);  
        }  
          
        return ops;  
    }  
      
    /** 
     * 获取学年度选项 
     * @param html HTML文档 
     * @return 返回学年度选项数组 
     */  
    public static String[] getXnd(String html){           
        return getOptions(html, FIND_XND);  
    }     
      
    /** 
     * 获取学期选项数组 
     * @param html HTML文档 
     * @return 学期选项数组 
     */  
    public static String[] getXqd(String html){           
        return getOptions(html, FIND_XQD);  
    }  
      
    /** 
     * 获取学生简要信息 
     * @param html HTML文档 
     * @return 返回学生简要信息数组 
     */  
    public static StuSimpleInfo getStuInfo(String html){  
        String[] info=null;  
        //(<span id="([\\s\\S]+?)">([\\s\\S]+?)</span>\\|)?<span id="(.+)">(.+?)</span>  
        String res="";  
        String pattern="<TR class=\"trbg1\">"  
                + "([\\s\\S]*?)<TD>([\\s\\S]*?)"  
                + "<span id=\"Labe(.+?)\">([\\s\\S]+?)</span>(\\|([\\s\\S]*?)<span id=\"Labe(.+?)\">([\\s\\S]+?)</span>)*";       
        Pattern p=Pattern.compile(pattern);  
        Matcher m=p.matcher(html);        
        if(m.find()){  
            res=m.group(0);  
            info=res.split("\\|");  
            pattern="<span id=\"Labe(.+?)\">([\\s\\S]+?):([\\s\\S]+?)</span>";  
            p=Pattern.compile(pattern);  
            for(int i=0;i<info.length;i++){  
                m=p.matcher(info[i]);  
                if(m.find()){  
                    info[i]=m.group(3);  
                }else{  
                    info[i]="";  
                }  
            }  
        }  
          
        return BeanFactor.createStuSimpleInfo(info);  
    }  
      
    /** 
     * 在HTML文档中提取课表 
     * @param html HTML文档 
     * @return 返回课表 
     */  
    public static ArrayList<Course> getCourseList(String html){  
          
        String courseTableHtml=findCourseTableHtml(html);//找到课表部分的HTML  
        ArrayList<Course> courses=new ArrayList<Course>();  
  
        String[] rows=courseTableHtml.split("</tr><tr>");//按上课时间分隔HTML  
        for(int i=2;i<rows.length;i+=2){  
              
            String r=rows[i];  
            String[] cols=r.split("</td><td([\\S\\s]*?)>");//按星期几分隔HTML  
              
            int j=1;  
            if(i==2||i==6||i==10){  
                j=2;  
            }  
              
            int x=1;  
            for(;j<cols.length;x++,j++){  
                String c=cols[j];  
                String[] info=c.split("<br>");  
                if(info[0].contains(" ")) continue;                  
                String[] tem=new String[4];  
                int t=0;  
                  
                for(int k=0;k<info.length;k++){  
                    String item=info[k].trim();  
                    if(item.equals("")){  
                        //处理同一时间不同周数的课程  
                        t=0;  
                        tem=new String[4];  
                        continue;  
                    }  
                    tem[t++]=item;  
                    if(t==4){  
                        Course course=BeanFactor.createCourse(tem, i-1, x);  
                        courses.add(course);  
                    }  
                }  
                  
            }  
              
        }  
                  
        return courses;  
    }     
      
}  

      然后还有一些封装类的代码就不贴上来了,后面有完整代码的链接


五、总结

        上面的HttpService类已经为实现了访问教务网的所有操作,利用这个HttpService,我们就能得到课程表的信息,然后就可以写一个界面将这些课程信息展示出来,我自己写了一个简单的界面,并放到了GitHub上,有兴趣的读者可以去看一下,地址是 https://github.com/EsauLu/JluzhJW
        另外,我还依照这些思路写了一个安卓的课表APP,由于安卓的一些特性,写这个APP时并没有采用HttpClient这个包而是用了另一个包OkHttpClient,这个课表APP的源码地址: https://github.com/EsauLu/CourseTable
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值