日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Java爬取frame的课程表_从爬取湖北某高校hub教务系统课表浅谈Java信息抓取的实现 —— import java.*;...

發布時間:2024/10/8 windows 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java爬取frame的课程表_从爬取湖北某高校hub教务系统课表浅谈Java信息抓取的实现 —— import java.*;... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原創文章與源碼,如果轉載請注明來源。

一、概述

整個系統用Java開發。我們現在要做的是類似于超級課程表、課程格子之類的功能:輸入一個學生的教務系統賬號、密碼,得到Ta的課程表信息。點擊進入課表查詢,我們發現了這樣的頁面:

這就是我們需要的結果。其實思路很簡單,用java訪問這個鏈接,拿到Html字符串,然后解析鏈接等需要的數據。

因此,我們發送HTTP請求GET?http://s.hub.hust.edu.cn/aam/report/scheduleQuery.jsp,這樣就可以等到課表的內容了。但是,這個頁面必須是在登錄之后才能訪問的,如果直接發送GET請求的話,系統會認為你沒有登錄,所以會拒絕你的請求(跳轉到登錄頁面),所以,在發送GET請求之前,必須實現模擬登錄。

二、JAVA中GET/POST請求的實現

在進行模擬登錄之前,我們需要了解一些基本知識。

在java中,實現執行http請求有多種方式,比如使用urlconnection等等,不過在這里我們使用apache-httpclient。HttpClient 是 Apache Jakarta Common 下的子項目,可以用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,并且它支持 HTTP 協議最新的版本和建議。

1 //1. 首先創建一個CookieStore用于存儲Cookie數據

2

3 CookieStore cookieStore = newBasicCookieStore();4

5 //2.創建httpclient,并關聯CookieStore

6

7 DefaultHttpClient client = newDefaultHttpClient();8 client.setCookieStore(cookieStore);9

10 client.getParams().setParameter(CookieSpecPNames.DATE_PATTERNS, Arrays.asList("EEE, dd MMM yyyy HH:mm:ss z")); //該代碼用于設置cookie中的expires時間日期格式。添加該代碼是因為華科網站使用的cookie日期格式不是標準格式。

創建GET請求:

1 HttpGet get = new HttpGet("http://xxxx");2 get.setHeader("xxx","xxx");3 get.setHeader("xxxx","xxxx");4 get.setHeader("Cookie","cookie");5 HttpResponse response =client.execute(get);6 get.releaseConnection();

創建POST請求:

HttpPost post = new HttpPost("http://xxxx");

post.setHeader("xxx","xxxx");

post.setHeader("xxxx","xxxx");

post.setHeader("Cookie","cookie");//對post請求發送參數

List nvps = new ArrayList();

nvps.add(new BasicNameValuePair("username", "111"));

nvps.add(new BasicNameValuePair("password", "xxx"));

post.setEntity(new UrlEncodedFormEntity(nvps,"utf-8"));

HttpResponse response = client.execute(post);

從CookieStore得到Cookie字符串

1 StringBuilder stringBuilder = newStringBuilder();2 for(Cookie cookie:cookieStore.getCookies()){3 String key =cookie.getName();4 String value =cookie.getValue();5 stringBuilder.append(key).append("=").append(value).append(";");6 }7

8 return stringBuilder.toString();

從HttpResponse對象中獲取執行的結果(輸入流)

1 InputStream inputStream =response.getEntity().getContent();2 //獲取結果的輸入流

從輸入流中獲取字符串,可以用如下的函數(注意編碼問題)

1 public static String in2Str(InputStream in) throwsIOException{2 BufferedReader rd = new BufferedReader(new InputStreamReader(in,"utf-8"));3 String line = null;4 StringBuilder sb = newStringBuilder();5 while ((line=rd.readLine())!=null) {6 sb.append(line).append("\r\n");7 }8 returnsb.toString();9 }

Jsoup解析

以上幾段程序代碼就是我們程序工作的核心了,在我的源碼中,對這些代碼進行了封裝,你可以輕松找到它們(在spider包中)。

三、模擬登錄的實現

一般地,在java web中,登錄可以由類似于如下的代碼實現:

前臺html的代碼如下:

1 2 用戶名

3

4 密碼

5

6

7

8

9

后臺action如下(spring mvc):

1 @RequestMapping("/login.action")2 publicString loginSubmit(HttpServletRequest request,HttpServletResponse response,3   @RequestParam("username") String username,@RequestParam("password") String password) {4   5

6     if(username==null||password==null){7 request.setAttribute("msg", "您的輸入有誤!");8 return "/login";9     }10     if(username.equals("")||password.equals("")){11 request.setAttribute("msg", "您的輸入有誤!");12 return "/login";13 }14   User user =userDao.getUser(username, password);15   if(user==null){16        //TODO 登錄失敗

17        return "xxx";18   }else{19       request.getSession().setAttribute("loginUser",user); //保存登錄后的用戶到session

20       //TODO 登錄成功

21        return "xxx";22   }23

24 }

其實登錄也就是發送POST請求,服務器接收到POST請求(Request)后,對其處理(查詢數據庫等),返回Response。

其中最關鍵的與身份驗證有關的操作就是request.getSession().setAttribute("loginUser",user) 了。將登錄后的用戶保存到session中,這樣,在訪問其他需要身份驗證的頁面時,服務器只需要判斷session中是否有該用戶,如果有就表示身份驗證通過,如果沒有則表示身份驗證失敗。而java中對于session的實現是依賴于cookie中的jsessionid屬性的(參考文檔),如果模擬出登錄請求后(也就是模擬一個POST請求),得到cookie(也就是得到jsessionid),下次請求時將cookie發送給服務器以表明身份,不就可以訪問帶有權限的URL了么?

首先我們需要下載webscrab,這個軟件有多強大這里就不細說了,大家可以自行百度下載地址。下載后是.jar格式,怎么運行不用我多說了吧。關于webscrab的使用見webscrab.pdf

(webscrab的核心設置)

1.攔截登錄時的POST請求:(如果不會請參考使用說明或者百度webscrab的使用)

這里我們需要這兩種信息:Parsed和URLEncoded,其中,Parsed是POST請求的URL和Header,而URLEncoded則是該請求發送的參數。

我們先看Parsed部分,Parsed部分是由Method、URL和響應頭(以表示的Map型結構)組成。Method表示該請求是POST請求還是GET請求;響應頭對應了HttpGet/HttpPost類中的setHeader方法,大多數Header不是必須的,但是在請求時,最好加上相同的Header,以免出現一些問題。例如:如果沒有Host(該值表示域名,例如url是http://www.abc.com/login.action,則該值就是www.abc.com)或者Referer頭(表示發起請求時的頁面,告訴服務器我是從哪里過來的,比如是http://www.abc.com/login.html),在某些情況下可能會出現404錯誤。【這可能是由于服務器設置了防盜鏈機制】

因此,最好的處理是將攔截到的Header,都添加到HttpGet/HttpPost中。

或者以一個HashMap的方式存儲:(spider.tools.hub.HubEventAdapter和SHubEventAdapter)

1 HashMap map = new HashMap<>();2 map.put("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");3 map.put("Referer", "http://hub.hust.edu.cn/index.jsp");4 map.put("Accept-Language","zh-CN,zh;q=0.8");5 map.put("User-Agent", useragent);6 map.put("Accept-Encoding", "gzip, deflate");7 map.put("Host", "hub.hust.edu.cn");8 map.put("Proxy-Connection", "Keep-Alive");9 map.put("Pragma", "no-cache");

遍歷它們,調用setHeader方法。

下面我們再來看URLEncoded部分,該部分表示POST請求發送給服務器的數據。我們發現,其中有三項數據username、password、ln。

我們發現,這里的password值并不是我們剛剛輸入的密碼,而似乎是一種加密之后的結果,查看http://hub.hust.edu.cn/index.jsp的源代碼,發現如下代碼:(第210行)

var password = $("input[name='password']").val();if(password==""){

alert("請輸入用戶密碼(Password)");

$("input[name='password']").focus();return false;

}

$("input[name='password']").val($.base64.encode(password));//我們要找的東西在這里!!!

很明顯,$.base64,這是base64加密,所以在我們發送POST請求之前,應該對密碼進行一次base64加密后再發送。(可以根據密碼長度判斷是什麼加密類型,一般都是base64加密,32位一般是MD5加密,再長一些則可能是AES加密,如果結果非常長則很可能是RSA加密。)

而ln值,你可以嘗試反復刷新頁面,反復提交、攔截,會發現每次ln值都會改變,對于這樣每次會改變的值,我們采取這樣的方式:

GET /index.jsp -> cookie、ln??- >POST /login.action

首先對首頁執行GET方法,獲取首頁的HTML內容,并保存cookie。、

接下來用Jsoup解析首頁的html內容,得到ln值。

最后將ln值與cookie,加上用戶輸入的用戶名、密碼一起POST到/login.action 。

3.中轉登錄

在發送POST請求后,使用(二)中提供的in2Str方法,得到返回結果,居然發現結果如下:

1

2

3

4

5

7

8

9

10

12

13

14 varurl=document.getElementById("url").value;15 document.form1.action=url+'hublogin.action';16 document.form1.submit();17

18

原來這就是華科中轉登錄的機制啊。還是一樣的發送POST請求

POST?http://s.hub.hust.edu.cn/hublogin.action

usertype,username,password,url,key1,key2,F_App。

注意:此時的域名已經改為http://s.hub.hust.edu.cn/了,那么Header中的Host和Refer值最好也改為http://s.hub.hust.edu.cn/。

4.返回

使用下面代碼獲取POST執行后的整型返回值:

int code = response.getStatusLine().getStatusCode();

如果code=302則登錄成功,否則登錄失敗。(302也就是表示登錄已經成功,可以跳轉到其他頁面了。)

四、課表的獲取

在第三部登錄成功之后,我們發現GET ?http://s.hub.hust.edu.cn/aam/report/scheduleQuery.jsp 似乎不包含我想要的課表信息,于是繼續使用webscrab。

點擊“課表查詢”,繼續攔截請求,通過幾次攔截,發現有一個請求應該包含我需要的課表信息。

因此,還是使用跟之前類似的方法,發送POST請求

POST http://s.hub.hust.edu.cn:80/aam/score/CourseInquiry_ido.action

start = 2016-02-29

end = 2016-04-11

別忘記帶上第三步(登錄后)的Cookie!

最后得到的結果如下:

當當~~當————

點擊下一月,URLEncoded變成了:

這樣的日期似乎比較亂啊,

如果將start設置為2016-03-01,end設置為2016-03-31,獲取的就是3月的課表。

至此,華科大教務系統課表爬取完成!

五、總結

我的代碼的編程思路:(用抽象語言表述)

1 //整體代碼用抽象Java語言表示,這些代碼只是表示設計思路。不能運行

2

3 Header header1 = {"refer","http://hub.hust.edu.cn/index.jsp","host":"hub.hust.edu.cn"}; //響應頭header1

4 Header header2 = {"refer","http://s.hub.hust.edu.cn/index.jsp","host","s.hub.hust.edu.cn"}; //響應頭header2

5

6 Get get = new Get ("http://hub.hust.edu.cn/index.jsp").header(header1); //進入首頁

7 Response res1 =get.execute();8 String content1 = res1.getContent(); //獲取index.jsp的html代碼

9 String ln = getln(Jsoup.parse(content1)); //使用jsoup解析index.jsp的html代碼,從中獲取出ln(input hidden name='ln'的value)

10

11 Post post = new Post("http://hub.hust.edu.cn/hubulogin.action").header(header1); //準備模擬登錄的,POST提交12

13 //添加post數據

14 post.add("username","123456789");15 post.add("password",base64encode("mypassword"));16 post.add("ln",ln)17

18 Response res2 = post.execute(); //執行post請求

19

20 Post post2 = new Post("http://s.hub.hust.edu.cn/hublogin.action").header(header2); //中轉登錄,注意header的變化

21 Document dform = Jsoup.parse(res2.getContent()); //得到返回的動態表單內容

22 post.add("usertype",getUserType(d));23 post.add("username",getUserName(d));24 post.add("password",getPassword(d));25 post.add("url",getURL(d));26 post.add("key1",getKey1(d));27 post.add("key2",getKey2(d));28 post.add("F_App",getFApp(d));29

30 Response res3 =post2.execute();31

32 if(res3.getStatusLine().getStatusCode()==302){33 syso("登錄成功");34 }else{35 syso("登錄失敗");36 return;37 }38

39

40 Post kbPost = new Post("http://s.hub.hust.edu.cn:80/aam/score/CourseInquiry_ido.action").header(header2); //獲取課表的post請求

41 kbPost.add("start","2016-03-01");42 kbPost.add("end","2016-03-30");43 Response res4 =kbPost.execute();44 if(res4.getStatusLine().getStatusCode()==200){45 syso(res4.getContent());46 }else{47 syso("服務器異常!");48 }

擴展:

你可以直接在我的基礎上擴展,適用于其他學校的“課程格子”。

你可以選擇繼承AbstractTask類來表示一項POST/GET請求任務,用getEvent方法來表示該任務的具體內容,最好是對SpiderTaskEvent使用適配器模式。

示例代碼如下:(這是基于另一個學校的教務系統實現)

1 public abstract class JwxtEventAdapter implementsSpiderTaskEvent{2

3 private static final String useragent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko";4 Listheaders;5

6 privateCookies cookies;7 publicJwxtEventAdapter(Cookies cookies){8 HashMap map = new HashMap<>();9 map.put("Accept","text/html, application/xhtml+xml, image/jxr, */*");10 map.put("Referer", "http://jwxt.hubu.edu.cn/");11 map.put("Accept-Language","zh-Hans-CN,zh-Hans;q=0.8,en-GB;q=0.5,en;q=0.3");12 map.put("User-Agent", useragent);13 map.put("Accept-Encoding", "gzip, deflate");14 map.put("Host", "jwxt.hubu.edu.cn");15 map.put("Proxy-Connection", "Keep-Alive");16 map.put("Pragma", "no-cache");17

18 headers =StringHeader.build(map);19 this.cookies =cookies;20 }21 publicJwxtEventAdapter(){22 this(null);23 }24

25 @Override26 public void beforeExecute(SpiderRequest request) throwsIOException {27 request.setTimeout(20000);28 request.setHeaders(headers);29 if(cookies!=null){30 request.setCookie(cookies);31 }32 }33

34 @Override35 public voidafterExecute(SpiderRequest request, SpiderResponse response)36 throwsIOException {37

38

39 }40

41 }

1 public class JwxtRandomTask extendsAbstractTask {2

3 privateString random;4

5 privateImage image;6

7 publicImage getImage(){8 returnimage;9 }10

11 /**

12 *@paramclient13 */

14 publicJwxtRandomTask(HttpClient client) {15 super(client);16

17 }18

19 publicString getRandom() {20 returnrandom;21 }22

23 @Override24 publicMethod getMethod() {25

26 returnMethod.GET;27 }28

29 @Override30 publicString getURL() {31

32 return "http://jwxt.hubu.edu.cn/verifycode.servlet";33 }34

35

36

37 @Override38 publicSpiderTaskEvent getEvent() {39

40 return newJwxtEventAdapter() {41

42 @Override43 public voidafterExecute(SpiderRequest request,44 SpiderResponse response) throwsIOException {45 image =ImageIO.read(response.getContentStream());46

47 }48 };49 }

我在寫這個程序的時候,確實遇到了一些麻煩,就比如本文提到的404的問題;以及我可能是有點急躁吧,一開始沒有注意到其實這個登錄action是有一次中轉的,導致后面的GET操作都被系統提示為非法操作。

確實做這個讓自己感慨萬千,大學幾年來一直難以踏踏實實的做一些事情,太浮躁,C語言、算法、Java等等都是不精,只學了一點皮毛。一個大三學生班門弄斧,滿紙荒唐言,如有錯誤還請各位大神批評和指出,非常感謝!最后感謝一下提供賬號的同學d=====( ̄▽ ̄*)b。

希望以后能越走越遠!import java.*;

ps.我的源碼下載地址:下載1下載2

總結

以上是生活随笔為你收集整理的Java爬取frame的课程表_从爬取湖北某高校hub教务系统课表浅谈Java信息抓取的实现 —— import java.*;...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。