Java中模擬瀏覽器訪問網頁(三)
轉載:https://blog.csdn.net/qq122627018/article/details/51473150一.前言
看完上一節中瀏覽器訪問網頁的行爲分析之後,你是不是很好奇在Java程序中要怎麼去訪問一個網頁呢?先來回想一下瀏覽器訪問網頁的最基本流程:
封裝請求->發送請求->接收響應->解析並作出動作
那麼在Java中,我們要完成這套動作,用到的就是HttpURLConnection這個類,他可以幫助我們去完成一個請求網頁的動作
二.如何發送一個請求
HttpUrlConnection實例
HttpUrlConnection是Java自帶的類,所以並不需要導入第三方的jar包,而在通常情況下,獲取HttpUrlConnection實例的方法是通過一個URL來打開一個連接從而獲取實例,如下:
HttpURLConnection conn = null;
try {
URL realUrl = new URL("www.163.com");
conn = (HttpURLConnection) realUrl.openConnection();
}catch (Exception e) {
//Url出錯
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
這裏值得注意的是,這樣僅僅是打開一個連接而已,此時並未發送請求,接下來要做的,是設置HttpUrlConnection的參數:
//設置post方法
conn.setRequestMethod("POST");
//不使用緩存
conn.setUseCaches(false);
// 發送POST請求必須設置如下兩行
conn.setDoOutput(true);
conn.setDoInput(true);
//讀取超時時間
conn.setReadTimeout(8000);
//連接超時時間
conn.setConnectTimeout(8000);
//這一句很重要,設置不要302自動跳轉,後面會講解到
conn.setInstanceFollowRedirects(false);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
到這裏,一個HttpUrlConnection的實例就準備好了,接下來繼續設置這個請求的其他數據
設置請求頭
設置請求頭也就是請求頭部,在第二節中也講解過請求頭部的作用,目的是告訴服務器一些關於客戶端的信息,有時候這些請求頭部也會被當作服務器驗證客戶端的一些參數,如Referer頭部,這個頭部會告訴服務器我在請求你這個網頁之前是從哪裏跳轉過來的。話不多說,下面上代碼:
conn.setRequestProperty(key, value);
- 1
其實也就一句代碼哈哈,但是一般情況下,都是自己封裝好參數和值在一個map集合中,然後通過循環設置在conn中,如下:
for (Map.Entry<String, String> entry : sendData.getHeaders()
.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
//Log.i("wang","header中包含:"+entry.getKey()+":"+entry.getValue());
}
- 1
- 2
- 3
- 4
- 5
設置參數
設置參數只有在post請求的時候才需要用到這個方法,因爲get請求是直接把參數封裝到url中;下面看看代碼:
//模擬參數
String pars = "name=w&class=12";
out = new PrintWriter(conn.getOutputStream());
// 發送請求參數
out.print(pars);
// flush輸出流的緩衝
out.flush();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
到這裏,我們已經準備好一個請求了,那怎麼發送給服務器呢?其實,在HttpUrlConnection中,並沒有發送請求這個方法,而是通過獲取返回碼的函數,來讓HttpUrlConnection把這個請求發送出去:
int responseCode = conn.getResponseCode();
- 1
接下來看看怎麼處理服務器的迴應
三.接收響應
判斷響應碼
從上面我們已經知道了怎麼獲取響應碼,在接收服務器返回給我們的數據之後,第一步就要判斷響應碼,在第二節中也說過,響應碼是服務器處理請求狀態的標識
在一般抓包的過程當中,200代表這服務器處理請求成功;302代表着重定向,也就是跳轉到另外一個地址;
但是,這裏要特別指出,不是說得到響應碼200就一定代表着你請求數據成功。舉個例子:在登錄的過程中,由於密碼錯誤網頁彈出提示框,此時得到的也是響應碼200,所以在這裏不能說你請求數據成功,很多時候還是要看情況而定。
處理響應頭
有人可能會問道,其實響應頭在實際應用中並沒有什麼用呀,爲什麼要去關注它;
其實響應頭在抓包過程中也扮演着重要的角色,具體體現在Location和Set-Cookie這倆個頭部
Location
location頭部就是當收到返回碼302的時候指定的轉發地址,所以在判斷返回碼是302的時候,必須取出相應頭中的location值,然後再次封裝請求進行訪問
Set-Cookie
set-cookie頭是服務器要求客戶端保存在本地的cookie值,所以這個頭部關係到在web訪問中一些”狀態的保持”,比如登錄狀態。關於這個頭部有必要舉個例子:
eg:當用戶訪問登錄頁面的時候,服務器會返回一串cookie值,此時用戶必須保存在本地,當點擊登錄按鈕的時候,客戶端會把此cookie還有用戶名密碼發送給服務器,當驗證通過時,每次訪問服務器的每個子頁面的時候客戶端都會帶上此cookie,以讓服務器驗證本用戶是否已經登錄
那上面的邏輯在Java程序中的處理方法就是:發送一個登錄頁面的請求,收到響應後取出響應頭中的set-cookie值保存在本地,當要進行模擬登錄的時候,把此值封裝到請求頭中的cookie一併發送,完成登錄。
處理響應正文
處理了響應頭之後,就到了我們的主角–響應正文了。獲取響應正文的方式:
BufferedReader in = null;
String result = "";
// 定義BufferedReader輸入流來讀取URL的響應
in = new BufferedReader(new InputStreamReader(
conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
Log.i("wang","line="+line);
result += line;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
此處獲取的result就是我們的響應正文,也就是html代碼.我們要的數據就在裏面。
四.實踐
臨時寫的一個模擬訪問網頁的demo:
HttpURLConnection conn = null;
try {
URL realUrl = new URL(url);
conn = (HttpURLConnection) realUrl.openConnection();
conn.setRequestMethod("GET");
conn.setUseCaches(false);
conn.setReadTimeout(8000);
conn.setConnectTimeout(8000);
conn.setInstanceFollowRedirects(false);
conn.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0");
int code = conn.getResponseCode();
if (code == 200) {
InputStream is = conn.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = in.readLine()) != null){
buffer.append(line);
}
String result = buffer.toString();
//subscriber是觀察者,在本代碼中可以理解成發送數據給activity
subscriber.onNext(result);
}
}catch (Exception e){
subscriber.onError(e);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
附上demo截圖: