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

        之前学了一些java web的编程,理解了web应用的原理后,就突然想到,可以用java模拟登录吉珠的教务系统,然后爬取里面的课表、成绩、个人信息等等数据,然后就可以写成一个简易的课表APP。


一、第三方工具

         这里我用到了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=";
	
}


        首先,我定义了一个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后端开发的都懂吧)。
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' οnclick=\"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\" οnchange=\"__doPostBack\\('xnd',''\\)\" language=\"javascript\" id=\"xnd\">([\\s\\S]+?)</select>";
				break;
			case FIND_XQD:
				pattern="<select name=\"xqd\" οnchange=\"__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
 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值