上篇说了怎么实现登录的原理以及实现,接下来就是实现如何获得课程表,成绩以及空课室的信息了。其实原理很简单,如果你真的有认真看上一篇的登录实现步骤的话,其实很快就会得到结果。
因为原理都差不多,这里我只说如何获取课程表的信息,因为其他的功能都和这个功能的数据获取差不多。
那么下面就来进行对课程表的获取把!
登录正方教务系统,然后点击"学生个人课表",我们可以看到以下这个界面
我们这时候就要用到上篇所教的HttpWatch进行抓包,注意要在点击"学生个人课表"进行Record,接下来我们就会获得以下信息
点击这个post请求,我们可以看到
是不是觉得很熟悉,没错,这个就是正方教务系统获取特定数据所需要的参数,所以按照我们之前那样把这些参数都加入到post中就可以得到对应的数据
那么我们看看我们究竟会得到什么数据?
之前没碰过html的人可能会惊呆了,这究竟是什么东西?如果觉得看到这个不知道是什么,请自己看下html,这里就不说了。
现在我们看上去可以看到我们的信息在里面了,但是里面夹杂着很多我们不需要的东西,那我们究竟要怎么获取到我们需要的数据?
在我接触java爬虫的时候,我也不知道究竟要怎么处理下载下来的html,但是有一天看到了hongyang大神的博客,学习了基本的java爬虫以及如何获取里面的信息,真的
觉得收益无穷,也是因为看了他的博客,我才会开启了这几个信息对java爬虫的兴趣,并进行对学校新闻的爬取,当然也包括这个。
所以如果这里看完之后觉得对html的数据解析不够明白,可以看一下hongyang大神的博客学习学习。
说了这么多废话,那么究竟怎么才能获取到html中的特定数据呢?没错,就是jsoup。通过jsoup进行html的解析。其实通过jsoup进行对html进行解析没什么难度,难度只是
在于你要分析你下载下来的html,然后根据一些标签的特点或者规律进行适当的解析,这是我在实现解析时候的越到的一个大困难。无疑,解析我学校的课程表真的很痛苦,因为它有些格式不是很好,所以解析的时候我尽量要避免。
下面来说一下究竟怎么解析html:
public class ExtractService
{
/**
* @param rule
* @return
*/
public static List<NewsInfo> extract(Rule rule)
{
// 进行对rule的必要校验
validateRule(rule);
List<NewsInfo> datas = new ArrayList<NewsInfo>();<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
NewsInfo data = null;
try
{
/**
* 解析rule
*/
String url = rule.getUrl();
String[] params = rule.getParams();
String[] values = rule.getValues();
String resultTagName = rule.getResultTagName();
int type = rule.getType();
int requestType = rule.getRequestMoethod();
List<NameValuePair> params1 = null;
if (params != null)
{
params1=new ArrayList<NameValuePair>();
for (int i = 0; i < params.length; i++)
{
NameValuePair nameValuePair=new BasicNameValuePair(params[i], values[i]);
params1.add(nameValuePair);
}
}
Document doc=null;
if(params1!=null){
String html=BaseApplication.getSearchHtml(url, params1);
doc=Jsoup.parse(html); //这里解析html,获取到<span style="font-family: Arial, Helvetica, sans-serif;">Document </span>
}else{
String html=BaseApplication.getHtml(url);
doc=Jsoup.parse(html);
}
<span style="color:#ff0000;">//这以上的代码只是为了获取html,关键代码就只有一句(<span style="font-family: Arial, Helvetica, sans-serif;">doc=Jsoup.parse(html); )这句,重点是在下面</span></span>
//处理返回数据
Elements results = new Elements();
switch (type) //我们可以看到html有很多class,id,selection等标签,所以通过switch来选出你需要获得的标签,然后获取到你所指定的那个范围,这样就更进一步忽略掉没用的信息了,这里需要自己看下网页源码理解下,尤其对html不熟的。
{
case Rule.CLASS:
results = doc.getElementsByClass(resultTagName);
break;
case Rule.ID:
Element result = doc.getElementById(resultTagName);
results.add(result);
break;
case Rule.SELECTION:
results = doc.select(resultTagName);
break;
default:
//当resultTagName为空时默认去body标签
if (TextUtil.isEmpty(resultTagName))
{
results = doc.getElementsByTag("body");
}
}
//以下就是对指定"body"范围中的内容进行解析,每个网页都不同,所以你要根据你自己需求去获取
for (Element result : results)
{
Elements links = result.getElementsByTag("p");
for (int i = 0; i < links.size(); i++)
{
Element unit_ele = links.get(i);
Element link = unit_ele.getElementsByTag("a").get(0);
String content=link.text();
String href = link.attr("href");
String title = link.attr("title");
Element h4_ele = unit_ele.getElementsByTag("span").get(0);
String from = h4_ele.attr("title");
Element h4_ele1 = unit_ele.getElementsByTag("span").get(1);
String date = h4_ele1.text();
data = new NewsInfo();
data.setLinkHref(href);
data.setTitle(title);
data.setFrom(from);
data.setDate(date);
data.setContent(content);
datas.add(data);
}
}
} catch (IOException e)
{
e.printStackTrace();
}
return datas;
}
/**
* 对传入的参数进行必要的校验
*/
private static void validateRule(Rule rule)
{
String url = rule.getUrl();
if (TextUtil.isEmpty(url))
{
throw new RuleException("url不能为空?");
}
if (!url.startsWith("http://"))
{
throw new RuleException("url的格式不正确?");
}
if (rule.getParams() != null && rule.getValues() != null)
{
if (rule.getParams().length != rule.getValues().length)
{
throw new RuleException("参数的键值对个数不匹配!");
}
}
}
}
public class Rule
{
<span style="white-space:pre"> </span>/**
<span style="white-space:pre"> </span> * 链接
<span style="white-space:pre"> </span> */
<span style="white-space:pre"> </span>private String url;
<span style="white-space:pre"> </span>/**
<span style="white-space:pre"> </span> * 参数集合
<span style="white-space:pre"> </span> */
<span style="white-space:pre"> </span>private String[] params;
<span style="white-space:pre"> </span>/**
<span style="white-space:pre"> </span> * 参数对应的�??
<span style="white-space:pre"> </span> */
<span style="white-space:pre"> </span>private String[] values;
<span style="white-space:pre"> </span>/**
<span style="white-space:pre"> </span> * 对返回的HTML,第�?次过滤所用的标签,请先设置type
<span style="white-space:pre"> </span> */
<span style="white-space:pre"> </span>private String resultTagName;
<span style="white-space:pre"> </span>/**
<span style="white-space:pre"> </span> * CLASS / ID / SELECTION
<span style="white-space:pre"> </span> * 设置resultTagName的类型,默认为ID
<span style="white-space:pre"> </span> */
<span style="white-space:pre"> </span>private int type = ID ;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>/**
<span style="white-space:pre"> </span> *GET / POST
<span style="white-space:pre"> </span> * 请求的类型,默认GET
<span style="white-space:pre"> </span> */
<span style="white-space:pre"> </span>private int requestMoethod = GET ;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>public final static int GET = 0 ;
<span style="white-space:pre"> </span>public final static int POST = 1 ;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>public final static int CLASS = 0;
<span style="white-space:pre"> </span>public final static int ID = 1;
<span style="white-space:pre"> </span>public final static int SELECTION = 2;
<span style="white-space:pre"> </span>public Rule()
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>public Rule(String url, String[] params, String[] values,
<span style="white-space:pre"> </span>String resultTagName, int type, int requestMoethod)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>super();
<span style="white-space:pre"> </span>this.url = url;
<span style="white-space:pre"> </span>this.params = params;
<span style="white-space:pre"> </span>this.values = values;
<span style="white-space:pre"> </span>this.resultTagName = resultTagName;
<span style="white-space:pre"> </span>this.type = type;
<span style="white-space:pre"> </span>this.requestMoethod = requestMoethod;
<span style="white-space:pre"> </span>}
上面只是想帮助你理解一下详细的jsoup解析是怎样的,接下来我放源码上来把
/**
* 查询个人课表方法
*
* @param xnd
* @param xqd
* @throws ClientProtocolException
* @throws IOException
* @return
*/
public static HashMap<String, HashMap<Integer, ArrayList<Course>>> queryStuCourse(String xnd, String xqd)
throws ClientProtocolException, IOException {
HttpClient client = new DefaultHttpClient();
int lastIndexOf = stuName.lastIndexOf("同学");
if(lastIndexOf!=-1)
stuName = stuName.substring(0, lastIndexOf);
System.out.println(stuName);
String newQueryStuCourseUrl = queryStuCourseUrl + stuNumber + "&xm="
+ stuName + queryStuCourseGnmkd;
System.out.println(newQueryStuCourseUrl);
String viewState = IOUtils.getViewState(newQueryStuCourseUrl, Cookie,
mainUrl + stuNumber);
HttpPost queryStuCoursePost = new HttpPost(newQueryStuCourseUrl);
queryStuCoursePost.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, false);
List<NameValuePair> stuCoursePair = new ArrayList<NameValuePair>();
stuCoursePair.add(new BasicNameValuePair("__EVENTTARGET", "xqd"));
stuCoursePair.add(new BasicNameValuePair("__EVENTARGUMENT", ""));
stuCoursePair.add(new BasicNameValuePair("__VIEWSTATE", viewState));
stuCoursePair.add(new BasicNameValuePair("xnd", xnd));
stuCoursePair.add(new BasicNameValuePair("xqd", xqd));
queryStuCoursePost.setHeader("Cookie", Cookie);
queryStuCoursePost.setHeader("Referer", mainUrl + stuNumber);
UrlEncodedFormEntity entitySource = new UrlEncodedFormEntity(
stuCoursePair);
queryStuCoursePost.setEntity(entitySource);
HttpResponse responseStuCourse = client.execute(queryStuCoursePost);
String html = IOUtils.getHtml(responseStuCourse.getEntity()
.getContent(), "GB2312");
Document docCourse = Jsoup.parse(html);
Elements eleCourse = docCourse.select("td");
HashMap<String, ArrayList<String>>hashMap=new HashMap<String, ArrayList<String>>();
System.out.println("eleCourse.size()"+eleCourse.size()+"");
//测试代码
// for (Element element : eleCourse) {
// System.out.println(element.text());
// }
以上是获取课程表的源码,后面的有些没有放上去,原因是每个学校所得出结果都有所不同,所以你们自己根据自己学校进行数据的封装吧,这里就不一一叙说了,因为
解析课程表的信息真的很坑,我不知是不是每个学校的数据都这样,我觉得吧,还是你们亲自动手会比较好。
这次的博客就先这样把,本人第一次写实战类的博客,觉得写的不怎么好,望见谅。这里不贴出大量的代码是因为本人觉得其实原理都差不多,如果你看了上一篇的博客你就知道究竟是怎么回事。再者因为本人研究了java爬虫两个星期,觉得把,还是自己动手起来效果会好很多,所以打算贴出一些重要的代码,其他的让你们自行补充。
望提点建议,本人将来还会打算写一篇基于人脸识别的签到系统,所以希望能写好点。
今天就到此为止把。