Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一)

        最近都在搞和爬虫相关的东西,在搞完学校新闻模拟登录后,就感觉有种一丢丢的成就感,所以心血来潮想自己弄一个教务系统出来。在之前实现模拟登陆的时候本人无法通过HttpWatch进行分析,因为登陆界面是在外网的时候才会出现,所以但是就用手机把网页下载下来进行分析,然后找出需要post的参数,然后实现模拟登录。按照这样的思路,无疑我会用这种思路去实现登录正方系统,但是结果尝试很多次都不行。结果通过HttpWatch观察发现post的时候还有一个隐藏的参数,所以之前才会行不通.


以下是效果图:

Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一)_第1张图片     Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一)_第2张图片     Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一)_第3张图片     Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一)_第4张图片   Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一)_第5张图片

实现以上的各种功能其实关键在于把协议给弄清楚。首先需要我们注意的是登录需要帐号,密码和验证码,而通过httpwatch不难发现,其实我们访问整个过程中我们都需要用到我们验证码所带的Cookie。换句话来说,我们要在获取到验证码图片的时候,获取到我们需要的Cookie信息。

以下是HttpWatch抓到验证码的信息:



通过获取验证码,我们会将cookie保存下来,保存下来有什么用?看看下面这图就知道了

以下是我登录正方系统后所抓到的信息:

Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一)_第6张图片

Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一)_第7张图片

我们可以看到我们请求登录的时候请求头所带的cookie正是我们刚刚获取到验证码的时候所带的cookie,这就是为什么我们获取到验证码时要保存cookie的原因。


接着我们再来看一下这个post请求里面的信息,里面有__ViewStat(我也不知道是什么,不过一起带着Post就好了)RadioButtonList1(单选按钮:学生...),txtUserName:账号,TextBox2:密码,txtSecretCode:验证码。当然RadioButtonList1后面乱码了我们不知道传什么东西,不过淡定,我们在Stream中可以看到有一个_VIEWSTATE,而这个key所对应的值正是我们所传的所有参数的一个字符串。

__VIEWSTATE=dDwyODE2NTM0OTg7Oz6IMxu8wRHiZevFvdItT8RVFJjAFQ%3D%3D&txtUserName=yournumber&TextBox2=yourkey&txtSecretCode=ctd3&RadioButtonList1=%D1%A7%C9%FA&Button1=&lbLanguage=&hidPdrs=&hidsc=

看吧,根据Stream中的值我们就可以知道RadioButtonList1的值。

说了那么多我们就直接亮出我们的代码把。

获取验证码:

/**
     * 验证码功能
     * 
     */
    public static Bitmap  getCode()
            throws UnsupportedOperationException, Exception {
        // 获取验证码
        HttpGet secretCodeGet = new HttpGet(secretCodeUrl);
        client = new DefaultHttpClient();
         HttpResponse responseSecret = client.execute(secretCodeGet);
        // 获取返回的Cookie
        Cookie = responseSecret.getFirstHeader("Set-Cookie").getValue();
        viewState = IOUtils.getViewState(indexUrl, "", "");        
        InputStream content = responseSecret.getEntity().getContent();
        final Bitmap bitmap = BitmapFactory.decodeStream(content);
//      client=null;不能执行这个代码因为登录的时候还要用到这个client
        return bitmap;
    }
当然我们需要获取到_VIEWSTATE:

/**
     * 获取隐藏字段的__VIEWSTATE值
     * 
     * @param url
     * @param cookie
     * @param referer
     * @return
     * @throws UnsupportedOperationException
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static String getViewState(String url, String cookie, String referer)
            throws UnsupportedOperationException, ClientProtocolException,
            IOException {
        HttpClient client = new DefaultHttpClient();
        HttpGet getViewState = new HttpGet(url);
        getViewState.setHeader("Cookie", cookie);
        getViewState.setHeader("Referer", referer);// 设置头信息
        String s = IOUtils.getHtml(client.execute(getViewState).getEntity()
                .getContent(), "GB2312");
        String viewstate = Jsoup.parse(s).select("input[name=__VIEWSTATE]")
                .val();
        return viewstate;
    }
以上的代码就可以获取到验证码以及对应的Cookie了。

下面我们实现登录的逻辑,按照上面的推理,我们要知道我们要传的参数就是我们下面的参数,记得要带cookie

Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一)_第8张图片


以下是实现登录功能的代码:

 /**
     * 登录功能
     * @param stuNumber
     * @param password
     * @param secret
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static boolean loginUser(String stusNumber, String password,String secret) throws ClientProtocolException, IOException
			 {
	stuNumber=stusNumber;
	HttpPost loginPost = new HttpPost(loginUrl);// 创建登录的Post请求
	// 阻止自动重定向,目的是获取第一个ResponseHeader的Cookie和Location  
	loginPost.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, false); 
        loginPost.setHeader("Cookie", Cookie);// 带上第一次请求的Cookie
        List nameValuePairLogin = new ArrayList();// 封装Post提交参数
        nameValuePairLogin
                .add(new BasicNameValuePair("__VIEWSTATE", viewState));// 隐藏表单值
        nameValuePairLogin
                .add(new BasicNameValuePair("txtUserName", stuNumber));// 学号
        nameValuePairLogin.add(new BasicNameValuePair("TextBox2", password));// 密码
        nameValuePairLogin.add(new BasicNameValuePair("txtSecretCode", secret));// 验证码
        nameValuePairLogin.add(new BasicNameValuePair("RadioButtonList1",
                identityStu));// 身份,默认学生
        nameValuePairLogin.add(new BasicNameValuePair("Button1", ""));
        nameValuePairLogin.add(new BasicNameValuePair("lbLanguage", ""));
        nameValuePairLogin.add(new BasicNameValuePair("hidPdrs", ""));
        nameValuePairLogin.add(new BasicNameValuePair("hidsc", ""));
		
	UrlEncodedFormEntity entity = new UrlEncodedFormEntity(
			        nameValuePairLogin, "GB2312");
			loginPost.setEntity(entity);
		HttpResponse responseLogin = client.execute(loginPost);
		
        // 第三步:判断提交数据是否成功,成功返回302
        if (responseLogin.getStatusLine().getStatusCode() == 302) {
            // 如果提交成功,带着Cookie请求重定向的main页面,并获取学生姓名
            HttpGet mainGet = new HttpGet(mainUrl + stuNumber);
            mainGet.setHeader("Cookie", Cookie);
            mainGet.setHeader("Referer", loginUrl);
            HttpResponse responseMain = client.execute(mainGet);
            InputStream is = responseMain.getEntity().getContent();
            String html = "";
            try {
                html = IOUtils.getHtml(is, "GB2312");
//                System.out.println(html);
            } catch (Exception e) {
                System.out.println("解析html失败!");
                e.printStackTrace();
            }
            stuName = Jsoup.parse(html).getElementById("xhxm").text();
            System.out.println("登录成功!欢迎您:" + stuName);         
            client=null;
            return true;
        } else {
            System.out.println("登录失败!");
            return false;
        }
	}
以上两部分代码就完美的实现了登录功能。

虽然看起来很简单,但是实际上这可能是这个app中最重要的一个部分。这个分析不仅仅用于这个app也可以用于其他网站的登录分析,比如开源中国,CSDN等,如果有兴趣都可以自己弄一个属于自己的一个客户端出来。

今天就先介绍登录的部分,下次再介绍一下如何获取课表,成绩,以及空课室查询






你可能感兴趣的:(Android实现正方系统的登录以及课程表,成绩获取和空课室的查询(一))