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

引言

HttpClient是java語言下一個支持http協議的客戶端編程工具包,它實現了HTTP協議的全部方法,可是不支持JS渲染。咱們在作一些小玩意時,有可能須要登陸某些網站獲取信息,那麼HttpClient就是你的好幫手,廢話很少說,進入實戰。java

一 登陸的實際意義

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

說到這裏cookie差很少講完了,那麼登陸究竟是怎麼回事?登陸就是服務器向你的瀏覽器寫cookie,若是僅僅是在你的計算機上寫cookie,那麼別有用心的人僞造一個cookie也有機會登陸網站,因此服務器會在內存中保留一份相同的信息,這個過程叫作session會話。若是你在網站點擊退出按鈕,服務器會把內存中的cookie清除掉,同時清除瀏覽器中有關登陸的cookie。知道了這些,咱們就能夠上手了。apache

二 找到登陸關鍵cookie

這裏咱們能夠用wireshark來抓包分析一下。打開知乎首頁,打開wireshark,開始監聽端口,輸入用戶名和密碼,點擊登陸,查看wireshark抓到的包。截圖以下:編程

201957_832G_1983603.png

202007_dTC6_1983603.png

202024_SEE9_1983603.png

202036_F8AS_1983603.png

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

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

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

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

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

三 使用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);
    }
}

代碼的流程是:

  1. 從知乎首頁獲取xsrf信息。

  1. post請求當中須要cookie信息,可是咱們第一步中沒有獲得cookie,請在瀏覽器中自行找到cookie添加進去,上邊的cookie是我找到的。

  2. 提交post請求,獲得登陸用cookie

  3. 隨便找一個須要登陸的子頁面,將獲得的cookie寫入到請求頭中,提交請求,查看是否已經登陸成功

四 結果驗證

204817_CjD5_1983603.png

204817_ziPZ_1983603.png

第一張圖顯示獲得cookie並登陸成功

第二張圖顯示已經進入須要登陸的界面

總結

  1. 當咱們須要登陸一個界面獲取信息的時候,咱們要知道登陸實際上作了什麼,那就是讀寫cookie,post數據。

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

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

更多文章:http://blog.gavinzh.com

相關文章
相關標籤/搜索