Android超级课程表实现原理_逍遥小小妖的博客-程序员资料

技术标签: Cookie  android  数据报  Android  

感觉有必要更新一下文章。很久之前看到的这篇博文,觉得写的不错,故转载收藏。之后陆续有人私信相关问题(要源码什么的),都没有过多的回复。

--------------------------------------------------------------------------------------------------

现在像超级课程表这样的项目很多,现在公司的项目“房管通”,抢票软件智行火车票都是同样的原理,模拟用户行为,发送http请求,获取页面(或是json/xml数据)、解析。

工作过程,简单的说,就是构造合法的http请求报文。这个合法的http请求报文需要三部分:url,form data,header(主要是cookie中的sessionId,当然有些网站会做一些header验证,比如携程ebooking需要origin和referer)。

这三部分都可以使用chrome的开发者工具(F12,web开发者的必备技能,不会自行解决)观察获得。

其次是程序实现,每种语言都会有相应的http sdk,java好像http client使用的多一点(很久没用,忘记了,不会的自行解决)。

恩,就是这样,说的很明白。下面的内容比较啰嗦,可以不用看。

--------------------------------------------------------------------------------------------------



超级课程表火了有一阵子,最近安装体验了下,对里面自动导入课表这个功能很好奇——不清楚各大教学平台网站的API情况下,怎么获得相应数据?

网上搜了下,找到这篇博文,讲解很详尽,做个收藏。


主要工作是抓包,然后再对数据报进行分析。

首先需要准备的工具是HttpWatch,这是抓包需要的工具,然后还有一个jar包,叫Jsoup,这是用来解析网页HTML代码的。其次所以要的类是HttpClient、HttpPost、HttpGet。


先来看看最后的效果图,我实现了获取教务平台的考试成绩和考试座位安排的数据,课程表数据一样的原理获取。





关于android的基本知识及我所用的相应组件就不介绍了,直接开始正文了。


一、使用HttpWatch抓取教务平台的数据。


安装好HttpWatch后,打开IE浏览器,打开HttpWatch,先别点记录,因为还没有进入教务平台网站的。  = =

这是我学校的教务平台网站地址 http://210.43.188.41/ ,进入后,选择用户登录。好的,此时点击HttpWatch上的记录。



然后输入学号密码, = = 这里我就打上马赛克了,如果开发者真的需要用我学校的教务平台来进行学习,我愿意给你我的学号密码,不过请私下联系我安静

输入学号密码后点击登录,等网页完全加载完毕后点击记录边上的取消,这个时候就要对抓下来的数据进行分析了。接下来的演示可能有点傻瓜制 = = 希望秒懂的人谅解一下像我这样的新手。

大家可以看到HttpWatch有上下两块界面,首先看到上面的界面,找到“方法”为Post的那行数据,单击,就可以看到下面的界面出现了相应的内容。首先我们打开POST数据。




大家可以看到有很多参数和数值,但是!!除了我打钩的这三个参数外,其余的参数对于我们开发客户端而言形同虚设。大家可能会问了,在之前那个登陆页面中,明明有验证码需要输入的啊,但为什么在POST数据中,连cCode(验证码)这个参数都形同虚设呢?关于这个问题,我问了很多人,可是最终得到的结果是。。。。应该是这个教务平台的BUG = =  所以大家先别介意没有输入验证码,我跟大家保证,我们不需要输入验证码,也可以登录!!!!得意


好的,在分析完POST数据后,我们点击另一个选项卡,“头信息”。


同样,在众多发送的头信息中,我们所需要的只是Cookie,Cookie是什么?从本质上讲,他可以看成你的身份证,也就是说你在接下来的网页操作中,Cookie可以证明操作对象是你而不是别人。好的,关于其余参数的作用,如果你对抓包很有兴趣的话可以继续深究,但是对我们现在做客户端已经无用了~安静

对了,其实还有一个参数还是相当重要的,那就是在HttpWatch中上方的那个页面中有一列叫做URL,这个就是我们Post或者Get的直接网址,一定要注意!!不然你Post的时候没有Post到相对应的网站就等于白Post了 = =



第一步基本就已经完成了,就是关于使用HttpWatch抓包和分析数据的事基本就已经搞定了~(不过这只是第一个抓包内容,之后还需要抓包的,就是抓成绩或者课表的页面)。



二、将抓下来的数据运用在代码中


 

[java]  view plain copy
  1. List<Cookie> cookies;                      //保存获取的cookie  
  2. HttpClient client = new DefaultHttpClient();                   
  3. HttpResponse httpResponse;     

       

[java]  view plain copy
  1. String uriAPI = "http://210.43.188.41/_data/index_LOGIN.aspx";  
[java]  view plain copy
  1. /* 建立HTTP Post连线 */  
  2. HttpPost httpRequest = new HttpPost(uriAPI);  
  3. List<NameValuePair> params = new ArrayList<NameValuePair>();  
[java]  view plain copy
  1. /** 
  2.  * 以下三个数据就是我们的之前在POST里的数据,不用在意验证码 
  3.  */  
  4. params.add(new BasicNameValuePair("PassWord""*****");   //这里的密码我用*取代了  
  5. params.add(new BasicNameValuePair("UserID""201150080223");    //这是学号  
  6. params.add(new BasicNameValuePair("Sel_Type""STU"));    //以学生身份登录  
[java]  view plain copy
  1. try {  
  2.     // 发出HTTP request  
  3.     httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));  
  4.     // 取得HTTP response  
  5.     httpResponse = client.execute(httpRequest);   //执行  
  6.     // 若状态码为200 ok  
  7.     if (httpResponse.getStatusLine().getStatusCode() == 200) {   //返回值正常  
  8.         // 获取返回的cookie  
  9.         cookies = ((AbstractHttpClient) client).getCookieStore().getCookies();  
  10.     } else {  
  11.     }  
  12. catch (Exception e) {  
  13.     e.printStackTrace();  
  14. }  

上面的代码应该还是比较易懂的,关于部分不熟悉的类请大家自行阅读API文档哈。

第二步的目的一是将三个数据(学号、密码、登陆身份)Post到教务网站上,另一个是获取到登陆成功后的cookie。


三、继续抓包,不过这次是非常有针对性的抓包

之前已经提到了,我们之所以在登陆页面进行了第一次抓包操作,完全只是为了登陆成功并且获取成功后的cookie,这样,我们才能带着cookie继续访问我们接下来想要访问的东西。下面我以成绩为例子演示,课程表也是一样的!!

在教务平台上找到成绩查询界面并进入。


同样,先别记录,你这时可以清除一下你之前抓下的数据 (= = 当然,如果你觉得不妨碍你分析抓下来的数据,你也可以不清除)。清除后,点击HttpWatch的记录,然后检索,这时HttpWatch上又会出现很多很多数据。我们继续分析。

同样的,按照第一次抓包的方法,我们先找到POST数据的选项卡。




这些就是我们刚才Post的数据,反正这些数据我们大体上能理解,比如说sel_xn就是select的学年的意思,sel_xq就是学期,按道理来说这个数据我们都应该在代码里Post的,但是经过我自己的尝试,第一个参数btn_search可以不用post,这个估计就是我们点击“检索”那下所产生的效果。好的,这个时候你可以去看看“头信息”里的cookie,你会发现这个cookie和我们之前的那个cookie是一样的 = = 这是当然的,因为这样才能说明从刚开始到现在一直是同一个对象在操作。


第三步的作用很明显,就是为了POST一些数据到我们想要查询的网页上。


慢着,这里一个非常非常非常重要的东西没有讲到!第三步其实还有一个作用的,那就是!!!!!大家点击“POST数据”边上的那个“内容”选项卡。




看到没?“内容”里的数据原来就是我们网页上成绩的HTML源代码!哈哈,大家懂了吧?其实抓包的目的很纯粹的!就是为了获取相应的网页信息。你像什么QQ农场外挂啥的其实都是抓包的原理哟!


好的,这样一来,我们大部分的事情就做完了,我们回忆一下之前的操作。

首先是在登陆页面抓包,从而获取相应的cookie,接着是在JAVA代码中实现POST过程,然后我们再进行抓包操作,对查询成绩页面进行的抓包,我们找到了我们所需要POST的数据和页面所返回的内容,这样我们就明朗了,我们只要合理的解析一下获取的HTML代码就可以了!不过在此之前,我们先把第三步的操作在JAVA代码里实现。


四、在代码里实现第三步操作


[java]  view plain copy
  1. String result = "";  


[java]  view plain copy
  1. /* 声明网址字符串 */  
  2.                         String uriAPI = "http://210.43.188.41/xscj/Stu_MyScore_rpt.aspx";  //这个网站之前说了,查看HttpWatch里相应的URL  
  3.                         /* 建立HttpPost联机 */  
  4.                         HttpPost httpRequest = new HttpPost(uriAPI);  
  5.                         List<NameValuePair> params = new ArrayList<NameValuePair>();  
  6.                         /** 
  7.                          * 以下六个参数必须要用 
  8.                          */  
  9.                         params.add(new BasicNameValuePair("sel_xn""2011")); // 学年  
  10.                         params.add(new BasicNameValuePair("SelXNXQ""2"));  
  11.                         params.add(new BasicNameValuePair("SJ""1"));  
  12.                         params.add(new BasicNameValuePair("sel_xq", term)); // 学期:0 第一学期,1 第二学期  
  13.                         params.add(new BasicNameValuePair("zfx_flag""0"));  
  14.                         params.add(new BasicNameValuePair("zfx""0"));  
  15.                         try {<span style="font-family: Arial, Helvetica, sans-serif;">//把之前的cookie放到此次POST所需要的头信息中</span>  
[java]  view plain copy
  1. httpRequest.setHeader("Cookie","ASP.NET_SessionId="+ cookies.get(0).getValue());  
  2. httpRequest.setEntity(new UrlEncodedFormEntity(params2, HTTP.UTF_8));  
  3. /* 发出HTTP request */  
  4. HttpResponse httpResponse2 = new DefaultHttpClient().execute(httpRequest3);  
  5. /* 若状态码为200 ok */  
  6. if (httpResponse2.getStatusLine().getStatusCode() == 200) {  
[java]  view plain copy
  1. <span style="white-space:pre">                              </span>//接下来的代码是为了把从网页获取到的内容读出来  
  2.                                 StringBuffer sb = new StringBuffer();  
  3.                                 HttpEntity entity = httpResponse2.getEntity();  
  4.                                 InputStream is = entity.getContent();  
  5.                                 BufferedReader br = new BufferedReader(new InputStreamReader(is, "GB2312"));  
  6.                                 //是读取要改编码的源,源的格式是GB2312的,安源格式读进来,然后再对源码转换成想要的编码就行  
  7.                                 String data = "";  
  8.                                 while ((data = br.readLine()) != null) {  
  9.                                     sb.append(data);  
  10.                                 }  
  11.                                 result = sb.toString();  //此时result中就是我们成绩的HTML的源代码了  
  12.                             } else {  
  13.                             }  
  14.                         } catch (Exception e) {  
  15.                             e.printStackTrace();  
  16.                         }  

老规矩,对于一些大家不熟悉的类依旧自行查看API文档。


五、使用Jsoup解析获取的HTML代码

好样的,做完第四步的时候其实我们已经基本完成了百分之80的操作了,用Jsoup解析说难不难,说易不易,我这里就只是把解析我所需要的内容进行一下讲解。

先上代码。


[java]  view plain copy
  1. private String filterHtml(String source) {  
  2.         if (null == source) {  
  3.             return "";  
  4.         }  
  5.         StringBuffer sff = new StringBuffer();  
  6.         String score[];  
  7.         int i = 0, j = 0;  
  8.         String html = source;  
  9.         Document doc = Jsoup.parse(html);   //把HTML代码加载到doc中  
  10.         Elements links_class = doc.select("td[width=23%]"); // 这是课程名,因为课程名的HTML标签事<td width=23% align=left>,然后我发现<span style="font-family: Arial, Helvetica, sans-serif;">width=23%是这个标签特有的,所以我就把它给提出来了</span>  
  11.         Elements links_grade = doc.select("td[width=5%]");  // 这是分数,原因同上  
  12.         score = new String[links_grade.size()];  
  13.         for (Element link_grade : links_grade) {  
  14.             score[i++] = link_grade.text();  
  15.         }  
  16.         for (Element link : links_class) {  
  17.             sff.append(link.text()).append(" : ").append(score[j]).append("\n");  
  18.             j = j+2;   //这里之所以+2是因为分数的标签是<td width=5% align=right>,而学分也是这样的标签,所以我就每提取一次分数标签跳过一次学分标签  
  19.         }  
  20.         html = sff.toString();  
  21.         return html;  
  22.     }  


这样函数中最后返回的html就是干净的代码了。总之关于Jsoup的解析并不是重点,因为解析HTML的方式还有很多的。



转自:http://blog.csdn.net/u010858238/article/details/9029653







版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/a386347993/article/details/10159803

智能推荐

Qt4过渡至Qt5_密苏里看雪的博客-程序员资料_qt5 qodbc插件 能否用在qt4

技术在不断进步,新知识也理应不断学习!Qt5的发布带给我无尽的好奇心,然而,受项目影响,一直使用VS2008 + Qt4.8也未曾及时更新。这几天,果断装上VS2010 + Qt5.1,开始研究。Qt4过渡到Qt5不算显著,然而,“模块化”的Qt代码也需要改变项目配置,如使用“headers”,和配置项目构建(如:改变*.pro文件)。QtWidgets作为一个独立的模块

macOS Catalina 10.15.7(19H2)原版CDR镜像_独行秀才的博客-程序员资料_macos catalina 10.15.7(19h2) v50.cdr

Mac 的本领,突飞猛进。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J2xKSjHl-1601024149703)(/Volumes/123/123/macOS Catalina-10.15.6(19G2021)]/640.png)音乐、播客,联袂登台iTunes 曾深刻影响了人们的视听娱乐方式。如今,音乐和播客这两款全新 app 携手登场,让一切再次改变。每款 app 都彻彻底底重新设计,只为让你能在 Mac 上尽享娱乐的精彩。请放心,你原来在 iTunes 资料

vue中axios接口的封装_codernmx的博客-程序员资料

api.js单独写在src目录下api目录写个api.jsimport axios from 'axios'// 登录export const index_info = function () { return axios.post('/api/home').then(res =&gt; { console.log(res); return res.data }).catch(err =&gt; { console.log("api登录错误", err) })};在需要调用

AndroidEventBus新特性:添加粘性事件、不需要手动注销事件总线_丿天下丶第一的博客-程序员资料

刚看了下作者发布的新版本AndroidEventBus v1.0.4版本,发现加了很多好东东,最大的两个特性就是添加了粘性sticky事件和无需手动注销事件 AndroidEventBus的github地址为:github

装服务器系统时无法找到介质,服务器安装介质未找到_狮心王546的博客-程序员资料

服务器安装介质未找到 内容精选换一换通过配置脚本,实现SAP HANA节点的HA功能(即HAE功能),提高SAP HANA节点的可靠性。公有云平台提供了一键式重置密码功能。弹性云服务器的密码丢失或过期时,如果您的弹性云服务器提前安装了一键式重置密码插件,则可以应用一键式重置密码功能,给弹性云服务器设置新密码。该方法方便、有效,建议您成功创建、登录弹性云服务器后,安装密码重置插件,具体操作请参见本节...

python读取nc文件并转换成csv_Python提取netCDF数据并转换为csv文件_weixin_39796238的博客-程序员资料

netCDF全称是network Common Data Format(网络通用数据格式),是由美国大学大气研究协会(University Corporation for Atmospheric Research,UCAR)的Unidata项目科学家针对科学数据的特点开发的,是一种面向数组型并适于网络共享的数据的描述和编码标准。目前,NetCDF广泛应用于大气科学、水文、海洋学、环境模拟、地球物理...

随便推点

[汇编语言] 汇编语言之IO操作 - 使用直接磁盘服务(Direct Disk Service——INT 13H)_跬步至以千里的博客-程序员资料

一、前言  最近参加三个一学习活动,学到了十七章,由于之前的实验都是在Windows系统下进行的,非常顺利,但这次实验让我吃了鳖,花了两天时间才找到一个不是特别令人满意的解决方案。所以打算记录在本博客,涨涨教训。   首先,阐述一下实验背景和环境,学习汇编语言的环境大多都是Windows或Liunx系统下,使用Dosbox0.74以及汇编语言三件套(masm,link,debug)环境,的确...

2019-6-23-win10-uwp-开发-CSDN-访问量统计-源代码_lindexi_gd的博客-程序员资料

title author date CreateTime categories win10 uwp 开发 CSDN 访问量统计 源代码 lindexi 2019-6-23 11:2:1 +0800 2018-2-13 17:23:3 +0800 Win10 UWP 我想得到我CS...

get ip address_ITZYF的博客-程序员资料

首先载入Winsock动态库,代码如下:int CIPAddressDlg::StartUp(){ WORD wVersionRequested; WSADATA wsaData; int err; wVersionReuqested=MAKEWORD(2,0); err=WSAStartup(wVersionReuqested, &wsaData);

pta冒泡法排序_缪同学嘞的博客-程序员资料_冒泡法排序pta

pta冒泡法排序输入1个正整数n(1&lt;=n&lt;=10),然后输入n个整数并存放在数组中,将这n个整数从大到小排序后输出,相邻数字间有一个空格,行末不得有多余空格。输入格式:输入第一行给出一个不超过10的正整数n。第二行给出n个整数,其间以空格分隔。输出格式:在一行中输出从大到小有序的数列,相邻数字间有一个空格,行末不得有多余空格。输入样例:475 71 77 76结尾无空行输出样例:77 76 75 71结尾无空行#include &lt;stdio.h&gt; in

清华社英语在线自动教程python版_qq_1846093422的博客-程序员资料_清华社英语在线刷题脚本

这里写自定义目录标题清华社英语在线自动教程python版清华社英语在线自动教程python版一、首先需要安装python运行环境,推荐下载python3.6以上,因为登录验证码识别库pil 需要用到levenstin 图像相似都对比,貌似低于3.5的版本不支持。安装时最好勾选添加python路径到系统,这样可以直接在命令行中调用。二、下载Vscode 开发工具,安装python插件python官网下载地址:(https://www.python.org/downloads/)三、复制代码到编_1671465600

oracle普通用户授予访问系统表权限方式_狸狸1009的博客-程序员资料_oracle赋权普通用户查看表的权限

## **oracle创建用户,并赋予其特定权限** ##1、cmd进入命令行输入输入【sqlplus /nolog】进入oralce控制台; 2、进入控制台输入【conn / as sysdba】,以管理员权限登录; 3、登录成功输入【create user 用户名 identified by 密码】,创建用户名密码; 4、创建成功,开始授予权限输入【grant ...

推荐文章

热门文章

相关标签