在Android上模拟登录学校正方教务系统查询成绩
这是在博客园里开博以来写的第一篇博客。
因为之前看过很多人都有发过关于模拟登录正方软件获取数据的文章,自己觉得挺好玩的便也去动手一做,开始还以为挺难的,但实际做起来还蛮简单的,当然其中还有些小插曲。
废话不多说,先po两张效果图:
界面做得比较随意,有空会再完善的。
接下来便说说是如何实现的了。
首先,你得有个抓包工具(其实用浏览器自带的f12工具应该也是可以的,就是比较麻烦),很多人都是用Httpwatch(貌似支持IE跟火狐),这里我就随波逐流,也用Httpwatch。安装好Httpwatch之后便可以直接打开浏览器登录教务系统抓包啦
在点击登录按钮的时候记得先点击记录。
登录进去之后便可以看到Httpwatch中有数据变化了。
这时先选中方法为Post的这一行(记下此时的URL,后面有用到),再选中Post数据来看看要提交的表单有哪些。
这里面我们只要用到上面圈出的五个参数。
第一个参数“_VIEWSTATE”要自己获得(获取登录首页的html内容然后在里面提取就行了);
第二个参数RadioButtonList1的乱码数值其实是“学生”(有的Httpwatch版本可以显示,有的则是乱码),提交表单时提交“学生”即可;
第三个参数TextBox2是密码;
第四个参数txtSecretCode是登录界面的验证码,有的学校系统可以直接绕过,我学校的则不行(开始看了别人的说可以直接填空写死,结果在这里被坑了好久,最后只能老老实实把验证码加上去),所以具体可不可以还得自己试试;
第五个参数是学号;
(每个学校提交的参数应该都是不同的,不过依葫芦画瓢就行了)
其实表单中还有一个更重要的参数:Cookie
Cookie的值在每一次提交的时候都得加上去,Cookie同“_VIEWSTATE”一样得自己先获得,不过不一样的是Cookie获取一次就可以,但“_VIEWSTATE”必须每次提交都得获取一次。
现在就来提交表单尝试登录
String URL = "http://jwgl.gdut.edu.cn/default2.aspx";//上面说到的URL HttpPost mHttpPost = new HttpPost(URL);//建立连接 mHttpPost.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, false);//禁止重定向 mHttpPost.setHeader("Cookie", Cookie);//设置Cookie //填写表单 List<NameValuePair> list = new ArrayList<NameValuePair>(); list.add(new BasicNameValuePair("__VIEWSTATE",viewstate)); list.add(new BasicNameValuePair("txtUserName",学号)); list.add(new BasicNameValuePair("TextBox2", 密码)); list.add(new BasicNameValuePair("RadioButtonList1","学生")); list.add(new BasicNameValuePair("txtSecretCode", 验证码)); //下面几个都直接填空写死即可(事实上下面几个只需添加Button1即可) list.add(new BasicNameValuePair("Button1", "")); list.add(new BasicNameValuePair("lbLanguage", "")); list.add(new BasicNameValuePair("hidPdrs", "")); list.add(new BasicNameValuePair("hidsc", "")); mHttpPost.setEntity(new UrlEncodedFormEntity(list, "GBK"));//提交表单 HttpResponse mHttpResponse = new DefaultHttpClient().execute(mHttpPost);// 响应请求 int statusCode = mHttpResponse.getStatusLine().getStatusCode();//状态码若为200则表示登录失败,此时需检查是否表单有误;若状态码为302则表示成功
当上述状态码为302时可继续往下,若为200请继续检查测试。
实际上要用到的地址是刚刚302下面的跳转的地址
我们再来对它建立连接尝试登录
String URL = "http://jwgl.gdut.edu.cn/xs_main.aspx?xh=" + 学号; HttpPost mHttpPost = new HttpPost(URL);//这里用post跟get都可以 //这里要比上次多添加一个值“Referer”,即将它的值置为此时的URL地址 mHttpPost.setHeader("Referer", URL); mHttpPost.setHeader("Cookie", Cookie);//Cookie还是原来的值 HttpResponse mHttpResponse = new DefaultHttpClient().execute(mHttpPost);//响应请求 //此时的状态码若为200则表示成功登录进入教务系统 if (httpResponse.getStatusLine().getStatusCode() == 200) { HttpEntity mHttpEntity = mHttpResponse.getEntity(); String html = EntityUtils.toString(mHttpEntity);//获取网页内容 String studentName = Jsoup.parse(html).getElementById("xhxm").text();//获取学生名字,后面查询成绩时需要用到 }
登录成功之后再回到浏览器先把刚刚抓取的数据清空,再重新点击记录,再进行成绩的查询,便可以抓取到数据了
同样我们找到方法为Post的这一行,选中它,同时记下它的URL,同样再在下面选中Post数据来看看需要提交的表单
这时我们需要提交的参数有上面四个,
第一个参数“_VIEWSTATE”同样需要自己重新获得(注意,这里的参数已经跟上面的不一样了,此时应该获取的是登录成功后的页面的html内容,然后再提取即可);
第二个参数Button1又乱码了,实际上是刚刚三个按钮的值
第三个参数ddlXN是学年;
第四个参数ddlXQ是学期;
(在这里如果点击按学期查询,那么就必须提交第三个跟第四个参数;如果点击按学年查询,那么就必须提交第三个参数;如果点击在校学习成绩查询,那么第三个跟第四个参数都不用提交,所以我们可以在代码中加个判断)
接下来我们用已有的参数来建立连接:
String URL = "http://jwgl.gdut.edu.cn/xscj.aspx?xh=" + 学号 + "&xm=" + 学生姓名 + "&gnmkdm=N121605";//学生姓名就是上面获取到的studentName HttpPost mHttpPost = new HttpPost(URL); //填写表单 List<NameValuePair> list= new ArrayList<NameValuePair>(); list.add(new BasicNameValuePair("__VIEWSTATE", viewstate)); list.add(new BasicNameValuePair("Button1", "按学期查询"));//这里我用学期查询,因此需要添加下面两个参数 list.add(new BasicNameValuePair("ddlXN", "2014-2015")); list.add(new BasicNameValuePair("ddlXQ", "1")); mHttpPost.setEntity(new UrlEncodedFormEntity(params, "GBK"));//提交表单 //这里我们同样需要设置两个头信息。后面的套路跟前面的是差不多的 mHttpPost.setHeader("Referer", "http://jwgl.gdut.edu.cn/xs_main.aspx?xh=" + 学号); mHttpPost.setHeader("Cookie", Cookie); HttpResponse mHttpResponse = new DefaultHttpClient().execute(mHttpPost); HttpEntity mHttpEntity = mHttpResponse.getEntity(); String html = EntityUtils.toString(mHttpEntity);//此时就获取到含有成绩信息的页面了 //用Jsoup将里面的课程成绩提取出来 Elements mElements = Jsoup.parse(html).select("td"); //再根据需要向mElements中提取需要的数据,再将其添加到listview中就大功告成了
当然,实现了成绩查询,其他的功能像什么课表查询、考试查询也都可以一一实现了,原理都是差不多的。