上篇說了怎麼實現登錄的原理以及實現,接下來就是實現如何獲得課程表,成績以及空課室的信息了。其實原理很簡單,如果你真的有認真看上一篇的登錄實現步驟的話,其實很快就會得到結果。
因爲原理都差不多,這裏我只說如何獲取課程表的信息,因爲其他的功能都和這個功能的數據獲取差不多。
那麼下面就來進行對課程表的獲取把!
登錄正方教務系統,然後點擊"學生個人課表",我們可以看到以下這個界面
我們這時候就要用到上篇所教的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爬蟲兩個星期,覺得把,還是自己動手起來效果會好很多,所以打算貼出一些重要的代碼,其他的讓你們自行補充。
望提點建議,本人將來還會打算寫一篇基於人臉識別的簽到系統,所以希望能寫好點。
今天就到此爲止把。