Android登入用戶端,驗證碼的擷取,網頁資料抓取與解析,HttpWatch基本使用

來源:互聯網
上載者:User

Android登入用戶端,驗證碼的擷取,網頁資料抓取與解析,HttpWatch基本使用

大家好,我是M1ko。在互連網時代的今天,如果一個App不接入互連網,那麼這個App一定不會有長時間的生命週期,因此Android網路編程是每一個Android開發人員必備的技能,博主是在校大學生,自學Android一年半多,正好通過一個類比登入校園網軟體,來給大家示範如何在網頁上抓取我們想要的資料,以及將資料Post給伺服器。如果有什麼錯誤或改進歡迎大家指正=-= ,如果想交流博主qq 136057505

好的廢話不多說看一下我們的重點

Httpwatch等軟體抓取Post請求 如何擷取驗證碼

使用Jsoup解析資料

Ok首先上項目Github網址:https://github.com/MikoGodZd/LoginNwuWeb1.git
下面是軟體的大家心裡能有項目的大體架構

一、Http基礎

有Http基礎的朋友都知道,我們是通過Get 與Post請求與伺服器進行互動的,Get顧名思義就是擷取資訊,Post就是想伺服器發請求,但是Post也可以用來擷取資訊並且比Get有很多優勢,我們這裡就是使用的Post。Java中有很多方式與伺服器進行串連,常見的有HttpUrlCollection,HttpClient。兩者的優缺點:

HttpUrlCollection優點:
- 輕量,拓展性強
- 節省資源
缺點:
- 代碼量大複雜

HttpClient優點:
- 便捷,代碼簡單
缺點:
-拓展性不足,耗費資源多

實際上在Android6.0中Google已經刪除了HttpClient的API官方理由是耗電量大,但是HttpCollection的代碼量實在是大,因此我們還是使用了HttpClient,只需在build.gradle中添加以下語句
android {
useLibrary 'org.apache.http.legacy'
}
即可。

二、伺服器位址的擷取 ##

我們要向伺服器Post資料要知道Post的地址是誰,這就要用我們的抓包軟體了,博主使用的是HttpWatch與Firefox的FireBug,兩個軟體的功能相互補充,兩個軟體基本的使用方法大家自行Google(百度,嘿嘿嘿=-=)
1.驗證碼的地址
ok首先開啟我們的校園網登入網頁:
http://jwxt.nwu.edu.cn/%28dlxrmg55j21wlaqv2z5rcdyi%29/Default2.aspx
我們點擊IE 中HttpWatch Record按鈕,然後重新整理這個網站我們可以看到如下的介面

我們能夠看到很多Get請求這些Get請求就能夠擷取開啟的介面的各個元素,右鍵G右方的網址,選擇Open in the new Tab就可以看到各個元素,細心(累死=-=)的尋找之後我們發現驗證碼的網址是
http://jwxt.nwu.edu.cn/%28dlxrmg55j21wlaqv2z5rcdyi%29/CheckCode.aspx 開啟後如顯示

2.登陸post地址
獲得驗證碼的地址之後,我們還要獲得登陸伺服器的地址,還是使用HttpWatch,我們輸入進去帳號密碼以及驗證碼之後,單擊登入開始抓取
開啟下面的POST DATA就可以看到我們發送的資料以及他們的類別
__VIEWSTATE
Button1
hidPdrs
hidsc
lbLanguag
RadioButtonLi
TextBox2 密碼
txtSecretCode 驗證碼
txtUserName 使用者名稱 這裡不給使用者名稱,有需要的QQ 加我136057505=-=
這些值很關鍵,我們在這裡面可以找到對應的值,如果沒有值那就是空,好的這些我們下面會詳細講,我們還沒有獲得Post地址,右鍵Post這一行Copy即可,ok這樣我們發送Post請求的地址就到手了。
http://jwxt.nwu.edu.cn/%28dlxrmg55j21wlaqv2z5rcdyi%29/Default2.aspx

三、登陸

1.驗證碼圖片的擷取
我們有了各種地址,下面就要登陸了,但是我們知道了帳號和密碼(嘿嘿嘿,就不告訴你們=-=),我們還要知道驗證碼,怎麼獲得圖片呢?上文中我們已經知道了驗證碼的地址了,我們可以Get請求,但之前也說過一般使用Post請求來進行,於是我們上代碼

  HttpPost httPost = new HttpPost(VERIFATIONURL);                HttpClient client = new DefaultHttpClient();                try {                    HttpResponse httpResponse = client.execute(httPost);                    byte[] bytes = new byte[1024];                    bytes = EntityUtils.toByteArray(httpResponse.getEntity());                    bmVerifation = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);                } catch (IOException e) {                    e.printStackTrace();                }

HttpClient的詳細用法大家自行Google這裡不詳細展開
VERIFATIONURL就是上文中的驗證碼地址,首先建立post請求,再建立一個Httpclient ,然後是HttpResponse即響應,我們擷取的伺服器的傳回值就在通過他擷取,我們建立一個byte數組,首先將響應中獲得的資料轉化為byte數組,然後通過 BitmapFactory.decodeByteArray(bytes, 0, bytes.length);方法將byte數組編譯為bitmap,這時候我們就獲得了驗證碼的Bitmap了,我們能直接ImageView.SetBitmap嗎?當然不能,首先第一點我們在網頁上擷取圖片是一個耗時操作,所以我們不能在主線程中進行,第二點只有在主線程中才能更新UI因此,我們使用Thread+Handler解決方案,上代碼:

private void DoGetVerifation() {        new Thread(new Runnable() {            @Override            public void run() {                HttpPost httPost = new HttpPost(VERIFATIONURL);                HttpClient client = new DefaultHttpClient();                try {                    HttpResponse httpResponse = client.execute(httPost);                    byte[] bytes = new byte[1024];                    bytes = EntityUtils.toByteArray(httpResponse.getEntity());                    bmVerifation = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);                } catch (IOException e) {                    e.printStackTrace();                }                Message msg = new Message();                msg.arg1 = 10;                handler.sendMessage(msg);            }        }).start();    }

主線程中接收到msg之後ivVerifation.setImageBitmap(bmVerifation);這樣我們就得到了驗證碼的圖片並且在主介面上顯示出來了

2.發送Post請求登入

我們目前知道了使用者名稱,密碼,驗證碼,下一步就是要登入了,登陸同樣是個耗時操作,當然也要開啟一個新的線程,這沒什麼好說的了,我們同樣是發送Post請求,上代碼:

private void DoLogin(final String user, final String password, final String verifation) {        new Thread(new Runnable() {            @Override            public void run() {                DefaultHttpClient defaultclient = new DefaultHttpClient();                HttpPost httpPost = new HttpPost(LOGINURL);                HttpResponse httpResponse;                //設定post參數                List params = new ArrayList();                params.add(new BasicNameValuePair("__VIEWSTATE", "dDwyODE2NTM0OTg7Oz6ZmvWn7xzjizifHN9MgLoDNTRtjQ=="));                params.add(new BasicNameValuePair("Button1", ""));                params.add(new BasicNameValuePair("hidPdrs", ""));                params.add(new BasicNameValuePair("hidsc", ""));                params.add(new BasicNameValuePair("lbLanguage", ""));                params.add(new BasicNameValuePair("RadioButtonList1", "%D1%A7%C9%FA"));                params.add(new BasicNameValuePair("TextBox2", password));                params.add(new BasicNameValuePair("txtSecretCode", verifation));                params.add(new BasicNameValuePair("txtUserName", user));                //獲得個人主介面的HTML                try {                    httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));                    httpResponse = defaultclient.execute(httpPost);                    Log.i("xyz", String.valueOf(httpResponse.getStatusLine().getStatusCode()));                    if (httpResponse.getStatusLine().getStatusCode() == 200) {                        StringBuffer sb = new StringBuffer();                        HttpEntity entity = httpResponse.getEntity();                        MAINBODYHTML = EntityUtils.toString(entity);                        IsLoginSuccessful(MAINBODYHTML);                    }                } catch (UnsupportedEncodingException e) {                    e.printStackTrace();                } catch (ClientProtocolException e) {                    e.printStackTrace();                } catch (IOException e) {                    e.printStackTrace();                }            }        }).start();    }

首先是建立post,client response,與前面無異,我們擷取資料的Post請求,比如說擷取驗證碼請求是不需要參數的,但是我們登入需要發送給伺服器 使用者名稱 密碼 驗證碼,於是我們為Post請求設定參數

 //設定post參數                List params = new ArrayList();                params.add(new BasicNameValuePair("__VIEWSTATE", "dDwyODE2NTM0OTg7Oz6ZmvWn7xzjizifHN9MgLoDNTRtjQ=="));                params.add(new BasicNameValuePair("Button1", ""));                params.add(new BasicNameValuePair("hidPdrs", ""));                params.add(new BasicNameValuePair("hidsc", ""));                params.add(new BasicNameValuePair("lbLanguage", ""));                params.add(new BasicNameValuePair("RadioButtonList1", "%D1%A7%C9%FA"));                params.add(new BasicNameValuePair("TextBox2", password));                params.add(new BasicNameValuePair("txtSecretCode", verifation));                params.add(new BasicNameValuePair("txtUserName", user));                    //獲得個人主介面的HTML                try {                    httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));                    httpResponse = defaultclient.execute(httpPost);                    Log.i("xyz", String.valueOf(httpResponse.getStatusLine().getStatusCode()));                    if (httpResponse.getStatusLine().getStatusCode() == 200) {                        StringBuffer sb = new StringBuffer();                        HttpEntity entity = httpResponse.getEntity();                        MAINBODYHTML = EntityUtils.toString(entity);                        IsLoginSuccessful(MAINBODYHTML);                    }                } catch (UnsupportedEncodingException e) {                    e.printStackTrace();                } catch (ClientProtocolException e) {                    e.printStackTrace();                } catch (IOException e) {                    e.printStackTrace();                }

這些參數就是我們之前使用HttpWatch擷取的Post data 只有類型沒有值的參數我們設定為“”空,使用httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));方法將我們設定的param 參數集合給httppost,下面和之前一樣,也是通過Response擷取響應值,只不過這裡返回的不是圖片而是赤果果的String=-=,IsLoginSuccessful這個函數是用來判斷我們是否登入成功,這就要用到我們下面要說的資料解析了。

四、資料解析

1.返回的響應?
我們登陸後會得到伺服器給我們的響應,我們在Firefox的Firebug(HttpWatch也可以個人感覺看響應值Firebug比較方便)上機型一次成功的登陸,看一下他究竟會給我們返回什麼
我們可以知道實際上響應值就是我們的網頁的HTML,如果登陸成功實際上就是返回個人首頁

那麼如果失敗呢?我們類比一次驗證碼錯誤如,可見同樣返回一個HTML

我們注意這一行

<script language='javascript' defer>alert('驗證碼不正確!!');document.getElementById('TextBox2').focus();</script>

這實際上是彈出一個視窗,提示我們驗證碼錯誤,下面我們就會利用裡面不同的提示來判斷我們登陸的狀態

2.使用Jsoup進行資料解析
我們建立之前提過的IsLoginSuccessful函數

   private void IsLoginSuccessful(String loginresult) {        Document doc = Jsoup.parse(loginresult);        Elements alert = doc.select("script[language]");        Elements success = doc.select("a[href]");        Message msg = new Message();        //先判斷是否登入成功,若成功直接退出        for (Element link : success) {            //擷取所要查詢的URL,這裡對應地址按鈕的名字叫成績查詢            if (link.text().equals("等級考試查詢")) {                Log.i("xyz", "登入成功");                msg.arg1 = 6;                handler.sendMessage(msg);                return;            }        }        for (Element link : alert) {            //重新整理驗證碼            DoGetVerifation();            //擷取錯誤資訊            if (link.data().contains("驗證碼不正確")) {                Log.i("xyz", "驗證碼錯誤");                msg.arg1 = 0;                handler.sendMessage(msg);            } else if (link.data().contains("使用者名稱不可為空")) {                Log.i("xyz", "使用者名稱不可為空");                msg.arg1 = 1;                handler.sendMessage(msg);            } else if (link.data().contains("密碼錯誤")) {                Log.i("xyz", "密碼或使用者名稱錯誤");                msg.arg1 = 2;                handler.sendMessage(msg);            } else if (link.data().contains("密碼不可為空")) {                Log.i("xyz", "密碼不可為空");                msg.arg1 = 3;                handler.sendMessage(msg);           ......        }    }

我使用的是一個開源的庫Jsoup進行解析當然還有很多方法,大家自行Google(百度=-=咋老躺槍)
http://www.open-open.com/jsoup/ Jsoup的中文API指南大家可以看一下
首先我們判斷登陸成功,我們在登陸成功的HTML中找到了如下語句

等級考試查詢

我們通過 Elements success = doc.select(“a[href]”);擷取到a href”開頭的資料 然後我們迴圈判斷是否存在等級考試查詢這一項,如果存在,那肯定返回的響應就是我們的個人首頁了,也就是說登陸成功,我們使用Thread+Handler在主線程中Toast提醒使用者
然後我們通過 Elements alert = doc.select(“script[language]”);擷取到script 開頭的語句,同樣迴圈判斷,這裡要注意的是,與a href不同的是,我們要用的是link.data(),前面用的是link.text();
JsoupAPI 這樣寫的

text()擷取常值內容text(String value) 設定常值內容data()擷取資料內容(例如:script和style標籤)
ok我們通過不同的類比操作抓取各種錯誤,這裡不詳寫 五、擷取個人資訊

我們登入到了個人首頁,我們想進一步擷取自己的資訊比如說四六級成績,怎麼辦呢?同樣還是抓取請求

跟擷取驗證碼網址的方法一樣,我們得到了成績表的網址
http://jwxt.nwu.edu.cn/(dlxrmg55j21wlaqv2z5rcdyi)/xsdjkscx.aspx?xh=2014117170&xm=鄒德宏&gnmkdm=N121606
前面http://jwxt.nwu.edu.cn/(dlxrmg55j21wlaqv2z5rcdyi)/是我們訪問的host是不變的,我們要做的就是擷取http://blog.csdn.net/mikogodzd/article/details/xsdjkscx.aspx?xh=2014117170&xm=鄒德宏&gnmkdm=N121606,這個問題困擾了很長時間,後來猛然發現這萬至竟然在前面說的deng’lu’cheng’登陸成功後返回的HTML中,所以還是使用Jsoup進行分析

 Document doc = Jsoup.parse(MAINBODYHTML);        Elements links = doc.select("a[href]");        StringBuffer sb = new StringBuffer();        for (Element link : links) {            //擷取所要查詢的URL,這裡對應地址按鈕的名字叫成績查詢            if (link.text().equals("等級考試查詢")) {                sb.append(link.attr("href"));            }        }        GETSCOREURL = sb.toString();

GETSCOREURL就是我們要的後半個地址,然後我們加上前半個,進行Post請求抓取即可
這裡返回的是一個Html的表格


  
學年 學期 等級考試名稱 准考證號 考試日期 成績 聽力成績 閱讀成績 寫作成績 綜合成績
2014-2015 2 CET4 610041151112625 201506 483 167 173 143 0
2015-2016 1 CET6 610041152209503 201512 376 126 143 107 0

同樣使用Jsoup

 private void parse(String parse) {        Document doc = Jsoup.parse(parse);        Elements trs = doc.select("table").select("tr");        for (int i = 0; i < trs.size(); i++) {            Elements tds = trs.get(i).select("td");            for (int j = 0; j < tds.size(); j++) {                String text = tds.get(j).text();                score[i][j] = text;                Log.i("xyz", score[i][j]);            }        }    }

解析完我們就得到成績的數組了

六、總結

博主大二黨自學Android開發1年半了,現在終於有入門的感覺了,這篇教程對新手來說坑能會有些難,但是一定要沉得住氣,博主剛下載HttpWatch那一會都懵逼了,啥都不懂,慢慢摸索之後終於有了頭緒,好了就這麼些,郵箱交流的朋友加我QQ 136057505=-=

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.