Android模擬登錄知乎

搞了幾年的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 block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.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("<span stylex="font-family: Arial, Helvetica, sans-serif;">_xsrf</span>",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<BasicNameValuePair> params = new LinkedList<BasicNameValuePair>(); 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 block e.printStackTrace(); } catch (ClientProtocolException e) { // TODO Auto- generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.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 block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; }

推薦閱讀:

華為的哪些有明顯過錯的做法應當被批評?
如何看待那岩開箱OPPO R11時吐槽雙攝後直播中斷?
既然 Android 免費,那 Google 是靠什麼賺錢的?
Android性能優化

TAG:模擬登錄 | Android |