首页 > 代码库 > HttpClient + Jsoup模拟登录教务处并获取课表

HttpClient + Jsoup模拟登录教务处并获取课表

  

1、概述

  最近想做一个校园助手类的APP,由于第一次做,所以打算先把每个功能单独实现,防止乱了阵脚。利用教务处登录获取课表和成绩等是一个基本功能,所以以获取课表为例实现了这个功能。完整代码点这里,尝试了好几次的,所以写的比较乱

2、涉及的关键知识

  首先,明确获取课表的流程:其实,获取课表就是让手机模拟浏览器,给服务器传去账号、密码,然后服务器会返回cookies(不懂自行百度),利用cookie就可以穿梭自如了,比如查课表。但是,浏览器登录时,返回的html文件浏览器是会自动解析成网页展现在我们面前的,但是APP就不行了,所以需要我们自己从html字符流中解析出我们需要的信息。就我自己的情况来看,模拟登录花了不少时间(这方面很不熟),解析html很快就解决了(可能是之前实践偶解析JSON)。

  这样一个APP主要涉及到3个重要知识点:

1、如何模拟登录:java有自己的HttpURLConnection,但是不够灵活,所以用 appache的HttpClient更方便

2、如何解析HTML:网上查一下,Jsoup很合适。

3、AsyncTask:显然获取网页并解析是不能再主线程进行的,所以需要使用异步任务。

4、回调函数:这个不是必须的,但是我为了降低程序耦合度把网络请求那部分单独成了一个类,这时候更新主UI就需要利用回调函数了,之后细说

3、模拟登陆(以窝工UPR为例)

  1、解析教务处登录界面,看到一些教程用的还是HttpWatch,确实过时了,显然直接Google浏览器F12就行了。如下图,选择Network

技术分享

  点一下登录,就可以看到一大堆信息,我们需要的是第一个:

技术分享

 

  点击就可以看到详细信息了:

技术分享

  重要的有两个,Cookie,拿到这个我们才能导出去访问,Form Data就是模拟登录时要提交(POST)的表单数据;

4、HTML解析

利用上一步模拟登录拿到的Cookie就可以去获取课表了,同理,需要解析网页,如下,点击我的课表

技术分享

 

  可以看到一大堆信息,找到需要的

技术分享

  这个Response就是会返回我们的字符流,我们需要的就是解析它,设计到Jsoup的详细使用就不细说了,自己也是今天才接触,

  总之借助以上两步就可以写出主要类Login.java的代码了,如下:

技术分享
  1 package com.example.upr.net;  2   3 import java.io.BufferedReader;  4 import java.io.IOException;  5 import java.io.InputStream;  6 import java.io.InputStreamReader;  7 import java.io.UnsupportedEncodingException;  8 import java.util.ArrayList;  9 import java.util.List; 10  11 import org.apache.http.HttpEntity; 12 import org.apache.http.HttpResponse; 13 import org.apache.http.NameValuePair; 14 import org.apache.http.client.ClientProtocolException; 15 import org.apache.http.client.HttpClient; 16 import org.apache.http.client.entity.UrlEncodedFormEntity; 17 import org.apache.http.client.methods.HttpGet; 18 import org.apache.http.client.methods.HttpPost; 19 import org.apache.http.cookie.Cookie; 20 import org.apache.http.impl.client.AbstractHttpClient; 21 import org.apache.http.impl.client.DefaultHttpClient; 22 import org.apache.http.message.BasicNameValuePair; 23 import org.jsoup.Jsoup; 24 import org.jsoup.nodes.Document; 25 import org.jsoup.nodes.Element; 26 import org.jsoup.select.Elements; 27  28 import com.example.upr.CompleteListener; 29  30 import android.R.integer; 31 import android.os.AsyncTask; 32 import android.provider.ContactsContract.Contacts.Data; 33 import android.util.Log; 34 import android.widget.Toast; 35  36 public class Login extends AsyncTask<Void, Void, String[][]>{ 37  38     private String zjh; 39     private String mm; 40     private String webPage; 41     private String [][] kebiao = new String[15][8]; 42     private CompleteListener listener; 43     public Login(String account, String password, CompleteListener listener) { 44         zjh = account; 45         mm = password; 46  47         this.listener = listener; 48     } 49     @Override 50     protected String[][] doInBackground(Void... arg0) { 51         List<NameValuePair> list = new ArrayList<NameValuePair>(); 52         list.add(new BasicNameValuePair("zjh", zjh)); 53         list.add(new BasicNameValuePair("mm", mm));//表单信息 54         String encode = "gb2312";//编码格式,从F12工具中可以找到 55         HttpClient httpClient = new DefaultHttpClient(); 56         List<Cookie> cookies; 57         try { 58             HttpEntity entity = new UrlEncodedFormEntity(list ,encode);//封装数据 59             HttpPost post = new HttpPost(com.example.upr.Constant.LOGIN_URL);//建立POST请求 60             post.setEntity(entity); 61             HttpResponse httpResponse = httpClient.execute(post); 62             String data, result; 63             if (httpResponse.getStatusLine().getStatusCode() == 200) {//登录成功 64                 cookies = ((AbstractHttpClient) httpClient).getCookieStore().getCookies();//获取Cookie 65                 HttpGet httpGet = new HttpGet("http://zhjw.dlut.edu.cn/xkAction.do?actionType=6"); 66                 httpGet.setHeader("Cookie", "JSESSIONID="+ cookies.get(0).getValue()+";"+ 67                         "NSC_kjbpxv-iuuq="+cookies.get(1).getValue());//注意分号 68                 httpResponse = new DefaultHttpClient().execute(httpGet); 69                  70                 StringBuffer sb = new StringBuffer(); 71                 entity = httpResponse.getEntity(); 72                 InputStream inputStream = entity.getContent(); 73                 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, encode)); 74                 while ((data = http://www.mamicode.com/br.readLine()) != null) {   75                     sb.append(data);  //读取返回的网页 76                 }   77                 result = sb.toString(); 78                 webPage = result; 79          80             } else { 81                 return null; 82             } 83         } catch (UnsupportedEncodingException e) { 84             e.printStackTrace(); 85             return null; 86         } catch (ClientProtocolException e) { 87             // TODO Auto-generated catch block 88             e.printStackTrace(); 89             return null; 90         } catch (IOException e) { 91             // TODO Auto-generated catch block 92             e.printStackTrace(); 93             return null; 94         } 95          96         Document document = Jsoup.parse(webPage); 97         if (document != null) { 98             Element element = document.getElementById("user");//通过id直接定位到数据 99             Elements trElements = element.select("tr");100             //以下是提取课表信息,每个网站不同,一下代码要解析的html放在最下面了101             for (int i = 0; i < trElements.size(); i++) {102                 Elements tdElements = trElements.get(i).select("td");103                 for (int j = 0; j < tdElements.size(); j++) {104                     String text = tdElements.get(j).text();105                     if (tdElements.size() == 1) {106                         continue;107                     } else if (tdElements.size()==9) {108                         if (j != 0) {109                             kebiao[i][j-1] = text;110                         }111                     }else {112                         kebiao[i][j] = text;113                     }114                     115                 }116             }117             return kebiao;118         } else {119             return null;120         }121 122     }123     @Override124     protected void onPostExecute(String[][] result) {125         super.onPostExecute(result);126         listener.onConnectFinish(result);//执行回调函数,更新主UI127     }128 }129 /*130 <table cellpadding="0" width="100%" class="displayTag" cellspacing="0" border="1" id="user">131             <tr>132               <td colspan="2" class="sortable">&nbsp;</td>133               <td width="13%" class="sortable">134                 <div align="center">星期一</div></td>135               <td width="13%" class="sortable">136                 <div align="center">星期二</div></td>137               <td width="13%" class="sortable">138                 <div align="center">星期三</div></td>139               <td width="13%" class="sortable">140                 <div align="center">星期四</div></td>141               <td width="13%" class="sortable">142                 <div align="center">星期五</div></td>143               <td width="13%" class="sortable">144                 <div align="center">星期六</div></td>145               <td width="13%" class="sortable">146                 <div align="center">星期日</div></td>147             </tr>148             <tr bgcolor="#FFFFFF">149               <td width="3%" rowspan="4">&nbsp;150                 <p class="style4">上午</p></td>151               <td width="11%">第1节(08:00-08:45)</td>152               <td>&nbsp; 计算机网络A_01(西部校区综合教学2号楼B406)153                 <br></td>154               <td>&nbsp; &nbsp;</td>155               <td>&nbsp; &nbsp;</td>156               <td>&nbsp; 编译原理_01(校部综合教学1号楼综151)157                 <br></td>158               <td>&nbsp; 计算机组成原理_01(西部校区综合教学2号楼B103)159                 <br></td>160               <td>&nbsp; &nbsp;</td>161               <td>&nbsp; &nbsp;</td></tr>162             <tr bgcolor="#FFFFFF">163               <td width="11%">第2节(08:50-09:35)</td>164               <td>&nbsp; 计算机网络A_01(西部校区综合教学2号楼B406)165                 <br></td>166               <td>&nbsp; &nbsp;</td>167               <td>&nbsp; &nbsp;</td>168               <td>&nbsp; 编译原理_01(校部综合教学1号楼综151)169                 <br></td>170               <td>&nbsp; 计算机组成原理_01(西部校区综合教学2号楼B103)171                 <br></td>172               <td>&nbsp; &nbsp;</td>173               <td>&nbsp; &nbsp;</td></tr>174             <tr bgcolor="#FFFFFF">175               <td width="11%">第3节(10:05-10:50)</td>176               <td>&nbsp; &nbsp;</td>177               <td>&nbsp; 面向对象程序设计_01(西部校区综合教学2号楼A301)178                 <br></td>179               <td>&nbsp; &nbsp;</td>180               <td>&nbsp; 人工智能_01(西部校区综合教学2号楼A101)181                 <br></td>182               <td>&nbsp; &nbsp;</td>183               <td>&nbsp; &nbsp;</td>184               <td>&nbsp; &nbsp;</td></tr>185             <tr bgcolor="#FFFFFF">186               <td width="11%">第4节(10:55-11:40)</td>187               <td>&nbsp; &nbsp;</td>188               <td>&nbsp; 面向对象程序设计_01(西部校区综合教学2号楼A301)189                 <br></td>190               <td>&nbsp; &nbsp;</td>191               <td>&nbsp; 人工智能_01(西部校区综合教学2号楼A101)192                 <br></td>193               <td>&nbsp; &nbsp;</td>194               <td>&nbsp; &nbsp;</td>195               <td>&nbsp; &nbsp;</td>196               <tr bgcolor="#FFFFFF">197                 <td colspan="9">&nbsp;198                   <p align="center" class="td2 style5">199                     <strong>午 休</strong></p>200                 </td>201               </tr>202             </tr>203             <tr bgcolor="#FFFFFF">204               <td width="3%" rowspan="4">&nbsp;205                 <p class="style4">下午</p></td>206               <td width="11%">第5节(13:30-14:15)</td>207               <td>&nbsp; 编译原理_01(校部综合教学1号楼综151)208                 <br></td>209               <td>&nbsp; 计算机组成原理_01(西部校区综合教学2号楼B103)210                 <br></td>211               <td>&nbsp; &nbsp;</td>212               <td>&nbsp; 计算机网络A_01(西部校区综合教学2号楼B406)213                 <br></td>214               <td>&nbsp; &nbsp;</td>215               <td>&nbsp; &nbsp;</td>216               <td>&nbsp; &nbsp;</td></tr>217             <tr bgcolor="#FFFFFF">218               <td width="11%">第6节(14:20-15:05)</td>219               <td>&nbsp; 编译原理_01(校部综合教学1号楼综151)220                 <br></td>221               <td>&nbsp; 计算机组成原理_01(西部校区综合教学2号楼B103)222                 <br></td>223               <td>&nbsp; &nbsp;</td>224               <td>&nbsp; 计算机网络A_01(西部校区综合教学2号楼B406)225                 <br></td>226               <td>&nbsp; &nbsp;</td>227               <td>&nbsp; &nbsp;</td>228               <td>&nbsp; &nbsp;</td></tr>229             <tr bgcolor="#FFFFFF">230               <td width="11%">第7节(15:35-16:20)</td>231               <td>&nbsp; 人工智能_01(西部校区综合教学2号楼A101)232                 <br></td>233               <td>&nbsp; &nbsp;</td>234               <td>&nbsp; &nbsp;</td>235               <td>&nbsp; &nbsp;</td>236               <td>&nbsp; 面向对象程序设计_01(西部校区综合教学2号楼A301)237                 <br></td>238               <td>&nbsp; &nbsp;</td>239               <td>&nbsp; &nbsp;</td></tr>240             <tr bgcolor="#FFFFFF">241               <td width="11%">第8节(16:25-17:10)</td>242               <td>&nbsp; 人工智能_01(西部校区综合教学2号楼A101)243                 <br></td>244               <td>&nbsp; &nbsp;</td>245               <td>&nbsp; &nbsp;</td>246               <td>&nbsp; &nbsp;</td>247               <td>&nbsp; 面向对象程序设计_01(西部校区综合教学2号楼A301)248                 <br></td>249               <td>&nbsp; &nbsp;</td>250               <td>&nbsp; &nbsp;</td>251               <tr bgcolor="#FFFFFF">252                 <td colspan="9">&nbsp;253                   <p align="center" class="td2 style5">254                     <strong>晚 饭</strong></p>255                 </td>256               </tr>257             </tr>258             <tr bgcolor="#FFFFFF">259               <td width="3%" rowspan="4">&nbsp;260                 <p class="style4">晚上</p></td>261               <td width="11%">第9节(18:00-18:45)</td>262               <td>&nbsp; 社会学*_886(校部综合教学1号楼综152)263                 <br></td>264               <td>&nbsp; 人类文明史*_887(校部材料馆材101)265                 <br></td>266               <td>&nbsp; &nbsp;</td>267               <td>&nbsp; &nbsp;</td>268               <td>&nbsp; &nbsp;</td>269               <td>&nbsp; &nbsp;</td>270               <td>&nbsp; &nbsp;</td></tr>271             <tr bgcolor="#FFFFFF">272               <td width="11%">第10节(18:55-19:40)</td>273               <td>&nbsp; 社会学*_886(校部综合教学1号楼综152)274                 <br></td>275               <td>&nbsp; 人类文明史*_887(校部材料馆材101)276                 <br></td>277               <td>&nbsp; &nbsp;</td>278               <td>&nbsp; &nbsp;</td>279               <td>&nbsp; &nbsp;</td>280               <td>&nbsp; &nbsp;</td>281               <td>&nbsp; &nbsp;</td></tr>282             <tr bgcolor="#FFFFFF">283               <td width="11%">第11节(19:50-20:35)</td>284               <td>&nbsp; 社会学*_886(校部综合教学1号楼综152)285                 <br></td>286               <td>&nbsp; 人类文明史*_887(校部材料馆材101)287                 <br></td>288               <td>&nbsp; &nbsp;</td>289               <td>&nbsp; &nbsp;</td>290               <td>&nbsp; &nbsp;</td>291               <td>&nbsp; &nbsp;</td>292               <td>&nbsp; &nbsp;</td></tr>293             <tr bgcolor="#FFFFFF">294               <td width="11%">第12节(20:45-21:30)</td>295               <td>&nbsp; &nbsp;</td>296               <td>&nbsp; &nbsp;</td>297               <td>&nbsp; &nbsp;</td>298               <td>&nbsp; &nbsp;</td>299               <td>&nbsp; &nbsp;</td>300               <td>&nbsp; &nbsp;</td>301               <td>&nbsp; &nbsp;</td></tr>302           </table>303 304 */
View Code

 

5、关于回调函数的使用

  这一部分之前完全没预料到,只是后来才发现,不用内部类,想更新UI就得用回调函数,其更深层次的思想是一种设计模式,还是自己学的太少!知识使用完全浮于表面。

6、Demo演示

技术分享

7、总结

  零零散散花了不少时间,一来确实第一次做类似工作,二来自己习惯非常不好,对于新工具,研究API和即学即用能力不强。明天应该好好研究一下HttpClientJsoup,达到熟练抓取各种网页的目的!毕竟这只是开始!现在的学习状态实在太低效了。

  以上。

HttpClient + Jsoup模拟登录教务处并获取课表