HttpClient4.4 登錄知乎(詳細過程)

jopen 9年前發布 | 60K 次閱讀 網絡工具包 HttpClient

引言

HttpClient是java語言下一個支持http協議的客戶端編程工具包,它實現了HTTP協議的所有方法,但是不支持JS渲染。我們在做一些小玩意時,有可能需要登錄某些網站獲取信息,那么HttpClient就是你的好幫手,廢話不多說,進入實戰。

一 登錄的實際意義

在HTTP橫行的今天,我們每天都要登錄一些網站,那么登錄的意義是什么呢?首先要對cookie要有一定了解。cookie是存放在本地的一些小文件,它由服務器發送命令,瀏覽器在本地讀寫。當訪問某些網站的時候,瀏覽器會檢查是否有所瀏覽網站的cookie信息,如果有則在發送訪問請求的時候攜帶上這些內容,服務器可以讀取到瀏覽器發送請求中的cookie信息,在回應請求時可以再寫cookie信息。cookie信息包括鍵值,內容,過期時間,所屬網站。

說到這里cookie差不多講完了,那么登錄到底是怎么回事? 登錄就是服務器向你的瀏覽器寫cookie ,如果僅僅是在你的計算機上寫cookie,那么別有用心的人偽造一個cookie也有機會登錄網站,所以服務器會在內存中保留一份相同的信息,這個過程叫做session會話。如果你在網站點擊退出按鈕,服務器會把內存中的cookie清除掉,同時清除瀏覽器中有關登錄的cookie。知道了這些,我們就可以上手了。

二 找到登錄關鍵cookie

這里我們可以用wireshark來抓包分析一下。打開知乎首頁,打開wireshark,開始監聽端口,輸入用戶名和密碼,點擊登錄,查看wireshark抓到的包。截圖如下:

HttpClient4.4 登錄知乎(詳細過程)

HttpClient4.4 登錄知乎(詳細過程)

HttpClient4.4 登錄知乎(詳細過程)

HttpClient4.4 登錄知乎(詳細過程)

第一張圖是瀏覽器post提交數據。

第二張圖是提交的信息,包括_xsrf,password,remember_me,email, 注意,提交的信息中包括cookie,_xsrf可以從知乎首頁中獲取

第三張圖是服務器返回的信息, 注意它的狀態是200,說明是成功的

第四章圖是服務器返回的數據, 注意它有三條cookie設置,以及帶有一個登錄成功與否的信息

通過上邊的步驟我們能知道什么呢?首先,發送登錄請求的時候帶有的cookie,以及post數據的格式,其次我們能拿到登錄用cookie信息(第四張圖)。

三 使用HttpClient構造登錄信息

HttpClient是怎樣模擬瀏覽器的呢?首先需要建立一個HttpClient,這個HttpClient是用來模擬一個瀏覽器。其次構造一個post請求,添加post數據信息以及cookie。詳細代碼如下:

import org.apache.http.*;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Lookup;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.impl.cookie.DefaultCookieSpecProvider;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**

  • Created by gavin on 15-7-23. */ public class HttpClientTest { public static void main(String[] args) {
     //創建一個HttpClient
     RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT).build();
     CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
     try {
         //創建一個get請求用來接收_xsrf信息
     HttpGet get = new HttpGet("http://www.zhihu.com/");
         //獲取_xsrf
         CloseableHttpResponse response = httpClient.execute(get,context);
         setCookie(response);
         String responseHtml = EntityUtils.toString(response.getEntity());
         String xsrfValue = responseHtml.split("<input type=\"hidden\" name=\"_xsrf\" value=\"")[1].split("\"/>")[0];
         System.out.println("xsrfValue:" + xsrfValue);
         response.close();
         //構造post數據
         List<NameValuePair> valuePairs = new LinkedList<NameValuePair>();
         valuePairs.add(new BasicNameValuePair("_xsrf", xsrfValue));
         valuePairs.add(new BasicNameValuePair("email", "xxxx@xxx.com"));
         valuePairs.add(new BasicNameValuePair("password", "xxxxx"));
         valuePairs.add(new BasicNameValuePair("remember_me", "true"));
         UrlEncodedFormEntity entity = new UrlEncodedFormEntity(valuePairs, Consts.UTF_8);
         //創建一個post請求
         HttpPost post = new HttpPost("http://www.zhihu.com/login/email");
         post.setHeader("Cookie", " cap_id=\"YjA5MjE0YzYyNGQ2NDY5NWJhMmFhN2YyY2EwODIwZjQ=|1437610072|e7cc307c0d2fe2ee84fd3ceb7f83d298156e37e0\"; ");
         //注入post數據
         post.setEntity(entity);
         HttpResponse httpResponse = httpClient.execute(post);
         //打印登錄是否成功信息
         printResponse(httpResponse);
         //構造一個get請求,用來測試登錄cookie是否拿到
         HttpGet g = new HttpGet("http://www.zhihu.com/question/following");
         //得到post請求返回的cookie信息
         String c = setCookie(httpResponse);
         //將cookie注入到get請求頭當中
         g.setHeader("Cookie",c);
         CloseableHttpResponse r = httpClient.execute(g);
         String content = EntityUtils.toString(r.getEntity());
         System.out.println(content);
         r.close();
     } catch (IOException e) {
         e.printStackTrace();
     } finally {
         try {
             httpClient.close();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
    
    } public static void printResponse(HttpResponse httpResponse)
         throws ParseException, IOException {
     // 獲取響應消息實體
     HttpEntity entity = httpResponse.getEntity();
     // 響應狀態
     System.out.println("status:" + httpResponse.getStatusLine());
     System.out.println("headers:");
     HeaderIterator iterator = httpResponse.headerIterator();
     while (iterator.hasNext()) {
         System.out.println("\t" + iterator.next());
     }
     // 判斷響應實體是否為空
     if (entity != null) {
         String responseString = EntityUtils.toString(entity);
         System.out.println("response length:" + responseString.length());
         System.out.println("response content:"
                 + responseString.replace("\r\n", ""));
     }
    
    } public static Map<String,String> cookieMap = new HashMap<String, String>(64); //從響應信息中獲取cookie public static String setCookie(HttpResponse httpResponse) {
     System.out.println("----setCookieStore");
     Header headers[] = httpResponse.getHeaders("Set-Cookie");
     if (headers == null || headers.length==0)
     {
         System.out.println("----there are no cookies");
         return null;
     }
     String cookie = "";
     for (int i = 0; i < headers.length; i++) {
         cookie += headers[i].getValue();
         if(i != headers.length-1)
         {
             cookie += ";";
         }
     }
     String cookies[] = cookie.split(";");
     for (String c : cookies)
     {
         c = c.trim();
         if(cookieMap.containsKey(c.split("=")[0]))
         {
             cookieMap.remove(c.split("=")[0]);
         }
         cookieMap.put(c.split("=")[0], c.split("=").length == 1 ? "":(c.split("=").length ==2?c.split("=")[1]:c.split("=",2)[1]));
     }
     System.out.println("----setCookieStore success");
     String cookiesTmp = "";
     for (String key :cookieMap.keySet())
     {
         cookiesTmp +=key+"="+cookieMap.get(key)+";";
     }
     return cookiesTmp.substring(0,cookiesTmp.length()-2);
    
    } }</pre>

    代碼的流程是:

    1. 從知乎首頁獲取xsrf信息。
    2. post請求當中需要cookie信息,但是我們第一步中沒有得到cookie,請在瀏覽器中自行找到cookie添加進去,上邊的cookie是我找到的。
    3. 提交post請求,得到登錄用cookie
    4. 隨便找一個需要登錄的子頁面,將得到的cookie寫入到請求頭中,提交請求,查看是否已經登錄成功

    四 結果驗證

    HttpClient4.4 登錄知乎(詳細過程)

    HttpClient4.4 登錄知乎(詳細過程)

    第一張圖顯示得到cookie并登錄成功

    第二張圖顯示已經進入需要登錄的界面

    總結

    1. 當我們需要登錄一個界面獲取信息的時候,我們要知道登錄實際上做了什么,那就是讀寫cookie,post數據。

    2. 獲取cookie時,需要從響應頭中獲取,當服務器發來新的cookie信息時需要及時寫入。

    3. 當我們能登錄一個網站的時候,如何對其內容進行操作,這里推薦jsoup,良心庫,仿jquery操作模式。

    原文 http://segmentfault.com/a/1190000003013451
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!