java爬蟲模擬預約座位
因爲近來準備考研,每天需要預約圖書館的座位好不麻煩,於是想着怎麼整一個代碼,自動幫我預約座位。主要需求就是每天凌晨預約 (搶)明天的座位。
一.模擬登陸
因爲圖書館的預約系統比較簡單,登陸都是不需要驗證碼的,這裏給出一個登陸界面圖形,如下所示:
這樣模擬登錄就很好實現了,詳見我的博客 Java 爬蟲實戰之模擬登陸
二.預約座位
在登陸成功之後,就可以開始預約座位了。這裏有如下幾個難點:
- 因爲在點擊“預約座位”之後,會有一個按鈕進行確認,這個確認怎麼在代碼中實現?
- 預約座位post請求頭的處理
其實第二個問題就是第一個問題的引申。我們知道現在大多數的網頁使用的都是ajax進行動態刷新網頁,這樣不用像服務器重新請求就可以刷新網頁了。在點擊“預約座位”之後肯定是進行了網頁的刷新(要麼是修改了表單,要麼是做了其他什麼操作),然後進行請求。
我之前的思路是:該怎麼在代碼中模擬這個點擊確認的功能,但是沒有抽象到想到:其實這個按鈕的功能實際上可能就是修改了請求中某個表單,或者是在請求頭中添加了某個字段而已!
有了這個思路的轉換,我就知道之前爲什麼預約座位不成功了。原因就是沒有找出動態刷新之後真正提交的請求 。
於是研究網頁刷新之後進行的操作,仔細對比無法實現功能的代碼已經瀏覽器的調試結果,發現一個重要的差異在於:代碼中的請求頭丟失瞭如下這個玩意兒:
這就是Ajax的確認按鈕之後修改的請求頭,而其他沒有任何變化。
根據網頁的顯示:其請求參數如下:
請求的報頭如下:
根據上面寫出下面預約座位的代碼:
/**
* 3.開始預約座位
*/
//設置請求數據
Map<String,String> info = new LinkedHashMap<String, String>();
String atDate ;//哪一天
String st ;//
String et ;//
//1.獲取日期
Date date = new Date();
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
//2.獲取當前天+1
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
calendar.add(calendar.DATE,+1);//明天:正數 ;昨天:負數
date=calendar.getTime();
atDate = df1.format(date);
st = atDate +" "+ start;
et = atDate +" "+ end ;
info.put("atDate",atDate);
info.put("sid",sid);
info.put("st",st);
info.put("et",et);
String param = JSON.toJSONString(info);
// 獲取連接
Connection con_reserve = Jsoup
.connect("http://?????.aspx");
con_reserve.header("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0");// 配置模擬瀏覽器
//因爲這個方法是Ajax 的一個動態方法,所以一定要加到請求頭中,否則無法生效
con_reserve.header("X-AjaxPro-Method","AddOrder");
con_reserve.cookies(login.cookies());
con_reserve.requestBody(param);
Response seatInfo = con_reserve.ignoreContentType(true)
.method(Method.POST)
.header("Content-Type", "application/json")
.execute();
System.out.println(seatInfo.statusCode());
System.out.println(seatInfo.body());
對上面的代碼存在的問題有:
post
請求參數一定要使用json
格式嘛?使用maps
的數據格式行不行?因爲之前登錄時,使用的數據格式就是map
,那麼按理來說,使用maps
應該也是可以的。cookie
登錄之後,使用的是登錄的cookie
,那麼使用之前第一次的cookie
行不行?
對上面代碼還可改進之處有:cookie
的本地磁盤化,避免下次再次請求。該怎麼實現?cookie
和session
之間的區別?ajax
技術的使用【如果真想熟練使用爬蟲技術的話】- 如果網絡通信存在問題,代碼一次預約位置不成功,該怎麼處理?
- 是否可以重複利用這個
connection
實例?還是說每次請求一個新的url,都需要一個新的connection
? - 是否應該將預約位置的代碼抽離到一個單獨的方法中?
- 是否應該針對“預約成功”或者“預約失敗”進行一個日誌的保留?
但是因爲最近沒有那麼多的時間,這些待完善的功能,我會再慢慢實現,儘量讓這個系統無bug。