作者:小邪
链接:https://zhuanlan.zhihu.com/p/23017942
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
搞了几年的Android开发,第一次写博客,这次就先分享一下用Android手机端如何模拟登陆知乎(首页)
1 抓包
要想实现模拟登录,那需要确定一下模拟登录的网站的登录逻辑是怎么样,并且要确定登录的协议以及参数是什么样的,因此首先要进行对该网站进行抓包。目前市场上的抓包工具有很多HttpWacth,wireShake等,今天就不先介绍这些工具怎么用了,就先使用Chrome的开发者工具进行抓包。首先用Chrome浏览器打开知乎网站(首页),打开开发者工具,在更多工具中选择开发者工具,选到Network选项,如图:
使用自己的知乎账号,登陆知乎,如下图:
通过抓包的过程中,我们可以看到,知乎网点击登录后,是通过一个Post请求,那么单击一下phone_num,可以看到,请求的URL、Header以及参数,如下图:
现在,URL、Header以及参数都确定了,但是参数中的_xsrf,我们不知道是什么参数,那么查看一下知乎登陆页面的源代码,我们可以看到这么一行:
同时,查看它的源代码,我们还可以考虑到这个登录,可能存在验证码,因此我们故意输错密码,看看第二次登陆是否有验证码,以及报什么错误,在程序中好处理,抓包方式同上,在此就不在赘述,这个登陆有时候会有验证码,链接是:
https://www.zhihu.com/captcha.gif?type=login
现在前期抓包工作完成,那么接下来就是如何实现
2 HttpClient+Jsoup实现
首先我们考虑到知乎的网站是HTTPS的,那么我们要让HttpClient支持HTTPS请求,我采用的是忽略证书的方式,具体实现方式,大家也都能百度到,如果有不会的,那么留言一下,我会整理一下自己的代码上传。
然后用Jsoup爬去知乎的页面,获取_xsrf的值,并保存Cookie:
public String getZHPager(String url){try {HttpGet get = new HttpGet(url);HttpResponse response = client.execute(get);LogUtil.v("rescode", response.getStatusLine().getStatusCode()+""); cookie=((AbstractHttpClient)client).getCookieStore().getCookies().get(0).getValue();LogUtil.v("cookie", cookie);String str = EntityUtils.toString(response.getEntity(), "UTF-8");LogUtil.v("rescode", response.getStatusLine().getStatusCode()+"");LogUtil.v("re", str);return str;} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}
public String getHtmlStr(String str){ try{Document doc;doc = Jsoup.parse(str); Elements links = doc.getElementsByTag("input"); for(Element e :links){ if(e.attr("name").toString().equals("_xsrf")){LogUtil.v("_xsrf",e.attr("value").toString());return e.attr("value").toString(); } } }catch(Exception e){ LogUtil.v("_xsrf", e.toString()); } return null;}
接下来就是请求,
public String HttpPostData(String username,String password){//long cTime=System.currentTimeMillis();_xsrf = getHtmlStr(getStr(ZhConfig.MainUrl));//Log.v("lt", lt);//client.getParams().setParameter(arg0, arg1)List params = new LinkedList();params.add(new BasicNameValuePair("remember_me","true"));params.add(new BasicNameValuePair("password",password));params.add(new BasicNameValuePair("_eventId","submit"));params.add(new BasicNameValuePair("_xsrf",_xsrf));params.add(new BasicNameValuePair("phone_num",username));HttpPost post = new HttpPost(LoginUrl);try {post.setEntity(new UrlEncodedFormEntity(params, "utf-8"));post.addHeader("Connection", "Keep-Alive");post.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");post.addHeader("Host", "www.zhihu.com");post.addHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)");post.addHeader("Referer", "https://www.zhihu.com/"); post.getParams().setParameter("http.protocol.allow-circular-redirects", true);//post.addHeader("Cookie","JSESSIONID="+cookie);post.addHeader("Origin", "https://www.zhihu.com");post.getParams().setParameter( "http.protocol.cookie-policy",CookiePolicy.BROWSER_COMPATIBILITY);HttpResponse response = client.execute(post);HttpEntity entity = response.getEntity();InputStream stream = entity.getContent();ByteArrayOutputStream bos=new ByteArrayOutputStream();byte[] buffer=new byte[1024];int len = 0;while((len=stream.read(buffer))!=-1){bos.write(buffer,0,len);}//byte[] dataImage=bos.toByteArray();bos.close();stream.close();//String str = EntityUtils.toString(response.getEntity(), "UTF-8");String str = new String (bos.toByteArray(),"UTF-8"); Log.v("result",str+"");if(!str.contains("\\u767b\\u5f55\\u6210\\u529f")){return "1";}else{return cookie;}//long tTime=System.currentTimeMillis();//Log.v("TAG", tTime-cTime+"");} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ClientProtocolException e) {// TODO Auto- generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return "";}
其中“ \\u767b\\u5f55\\u6210\\u529f “这个”登陆成功“ 编码,写这篇博客时,还没有仔细看它的编码是什么,大家可以具体看一下,最后注意的一下就是有验证码登陆的时候,就是请求一下验证码图片(如下),登录时候添加一个参数params.add(new BasicNameValuePair("captcha", captcha)); 即可。
public Bitmap getLoginYzm(){HttpGet get = new HttpGet(ZhConfig.YZMUrl);get.addHeader("Connection", "Keep-Alive");get.addHeader("Content-Type", "application/x-www-form-urlencoded");get.addHeader("Host", "www.zhihu.com");get.addHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)");get.addHeader("Referer", "https://www.zhihu.com/");HttpResponse res;try {res = client.execute(get);HttpEntity entity = res.getEntity(); InputStream in =entity.getContent(); ByteArrayOutputStream bos=new ByteArrayOutputStream(); byte[] buffer=new byte[1024]; int len = 0; while((len=in.read(buffer))!=-1){ bos.write(buffer,0,len); } byte[] dataImage=bos.toByteArray(); bos.close(); in.close(); Bitmap bitmap =BitmapFactory.decodeByteArray(dataImage, 0, dataImage.length); return bitmap;} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}