转载

HttpClient4.4 登录知乎(详细过程)

引言

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。详细代码如下:

javaimport 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信息。
  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操作模式。

正文到此结束
Loading...