天天看點

HtmlUnit實作的網站登入

http://foxswily.iteye.com/blog/644353

http://foxswily.iteye.com/blog/644353

最近壇子裡接連出現基于httpclient登入網站的文章,也湊個熱鬧,分享一點基于htmlunit的登入經驗

謹以此文祭奠我剛剛逝去的滑鼠

----------------------------------------------分割線---------------------------------------------------

HtmlUnit 目前最新版本2.7(2010-04-15 Foxswily本人确認)

基于httpclient封裝(甚至已經做好啟用httpclient4的準備),模拟浏覽器操作,JavaScript支援較全面,包括主流的jQuery類庫,這也是它的強大之處,一般網站的JS屏蔽可以輕松突破。

舉例說明

Java代碼  

HtmlUnit實作的網站登入
  1. //建立浏覽器,可以選擇IE、FF等等  
  2. WebClient client = new WebClient(BrowserVersion.INTERNET_EXPLORER_7);  
  3. //擷取某網站頁面  
  4. HtmlPage page = client.getPage("http://xxx.com");  
  5. //擷取某頁面元素,可通過id或name,(具體方式很多 --Foxswily)  
  6. HtmlElement elmt = page.getElementById("someid");  
  7. //HtmlElement elmt = page.getElementByName("somename");  
  8. //此例以文本框為例,先點選,再輸入,完全跟真浏覽器行為一緻  
  9. elmt.click();  
  10. elmt.type("somewords");  
  11. //擷取按鈕  
  12. HtmlButton loginBtn = (HtmlButton)page.getElementById("btnId");  
  13. //點選并獲得傳回結果  
  14. Page resultPage = loginBtn.click();  
  15. //結果拿到了,想幹啥您随意  
  16. log.debug(resultPage.getWebResponse().getContentAsString());  

沿着這個思路展開一下,模拟登入不再需要破解什麼js邏輯,使用者實際做什麼代碼就模拟什麼,輕松多了    

額外的友情提示,Foxswily本人曾在登入使用者量衆多的discuz論壇時發現個小問題(已送出bug)

造成登入後跳轉失效,如有雷同參照解決吧

問題描述

    HtmlPage.executeRefreshIfNeeded()

when html header has meta like "<META HTTP-EQUIV="Refresh" CONTENT="3 URL=h

ttp://www.some.org/some.html">" it throws NumberFormatException.

cause there is no ";" after "3" in the content.

some forum sites have this bad writting html page.

大意就是,自動跳轉格式有問題,htmlunit解析不了,直接Exception了,改寫HtmlPage的一個方法後通過。

Java代碼  

HtmlUnit實作的網站登入
  1. private void executeRefreshIfNeeded() throws IOException {  
  2.     // If this page is not in a frame then a refresh has already happened,  
  3.     // most likely through the JavaScript onload handler, so we don't do a  
  4.     // second refresh.  
  5.     final WebWindow window = getEnclosingWindow();  
  6.     if (window == null) {  
  7.         return;  
  8.     }  
  9.     final String refreshString = getRefreshStringOrNull();  
  10.     if (refreshString == null || refreshString.length() == 0) {  
  11.         return;  
  12.     }  
  13.     final double time;  
  14.     final URL url;  
  15.     int index = refreshString.indexOf(";");  
  16.     final boolean timeOnly = (index == -1);  
  17.     if (timeOnly && refreshString.indexOf(" ") == -1) {  
  18.         // Format: <meta http-equiv='refresh' content='10'>  
  19.         try {  
  20.             time = Double.parseDouble(refreshString);  
  21.         } catch (final NumberFormatException e) {  
  22.             if (LOG.isErrorEnabled()) {  
  23.                 LOG.error("Malformed refresh string (no ';' but not a number): "  
  24.                         + refreshString, e);  
  25.             }  
  26.             return;  
  27.         }  
  28.         url = getWebResponse().getRequestSettings().getUrl();  
  29.     } else {  
  30.         if (refreshString.indexOf(";") == -1) {  
  31.             index = refreshString.indexOf(" ");  
  32.         }  
  33.         // Format: <meta http-equiv='refresh'  
  34.         // content='10;url=http://www.blah.com'>  
  35.         try {  
  36.             time = Double.parseDouble(refreshString.substring(0, index).trim());  
  37.         } catch (final NumberFormatException e) {  
  38.             if (LOG.isErrorEnabled()) {  
  39.                 LOG.error("Malformed refresh string (no valid number before ';') "  
  40.                         + refreshString, e);  
  41.             }  
  42.             return;  
  43.         }  
  44.         index = refreshString.toLowerCase().indexOf("url=", index);  
  45.         if (index == -1) {  
  46.             if (LOG.isErrorEnabled()) {  
  47.                 LOG.error("Malformed refresh string (found ';' but no 'url='): "  
  48.                         + refreshString);  
  49.             }  
  50.             return;  
  51.         }  
  52.         final StringBuilder buffer = new StringBuilder(refreshString  
  53.                 .substring(index + 4));  
  54.         if (buffer.toString().trim().length() == 0) {  
  55.             // content='10; URL=' is treated as content='10'  
  56.             url = getWebResponse().getRequestSettings().getUrl();  
  57.         } else {  
  58.             if (buffer.charAt(0) == '"' || buffer.charAt(0) == 0x27) {  
  59.                 buffer.deleteCharAt(0);  
  60.             }  
  61.             if (buffer.charAt(buffer.length() - 1) == '"'  
  62.                     || buffer.charAt(buffer.length() - 1) == 0x27) {  
  63.                 buffer.deleteCharAt(buffer.length() - 1);  
  64.             }  
  65.             final String urlString = buffer.toString();  
  66.             try {  
  67.                 url = getFullyQualifiedUrl(urlString);  
  68.             } catch (final MalformedURLException e) {  
  69.                 if (LOG.isErrorEnabled()) {  
  70.                     LOG.error("Malformed URL in refresh string: " + refreshString, e);  
  71.                 }  
  72.                 throw e;  
  73.             }  
  74.         }  
  75.     }  
  76.     final int timeRounded = (int) time;  
  77.     getWebClient().getRefreshHandler().handleRefresh(this, url, timeRounded);  
  78. }  

分享到: 

HtmlUnit實作的網站登入
HtmlUnit實作的網站登入

logback的SizeBasedTriggeringPolicy |  jQuery Validation alert第一個錯誤的方法

  • 2010-04-15 10:36
  • 浏覽 5969
  • 評論(27)
  • 論壇回複 / 浏覽 (24 / 17101)
  • 分類:程式設計語言
  • 相關推薦
評論

27 樓  ricien 2013-06-27   我登入人人之類的都登入不上去,無法跳轉請問一下是什麼問題啊 26 樓  jccmjl 2012-04-10   <frameset cols="*,1024,*" frame framespacing="0px" >  

  <frame src="blank.jsp" scrolling="no" noresize> 

  <frameset rows="90,*" cols="*" frame framespacing="0"> 

    <frame src="header.jsp" rows="90,*" scrolling="no" noresize name="header"  > 

    <frameset cols="200,*" frame framespacing="0"> 

      <frame src="menu.faces" scrolling="auto" noresize  name="menu"  > 

      <frame src="./SysManager/bulletin.faces?bbstype=2" scrolling="auto" noresize  name="body"  > 

    </frameset> 

   </frameset> 

我登入成功以後傳回到frame架構這裡,不知道如何往下寫了》。。。。 25 樓  alosin 2011-03-21   是以已經放棄HtmlUnit了!! 24 樓  Foxswily 2011-03-16   諸如此類的麻煩挺多,随便一個不起眼的地方對解析都是災難 23 樓  alosin 2011-03-15   Foxswily 寫道 看懂了HtmlUnit自然知道這種送出和普通按鈕沒什麼差別,僅僅在于你取的是Link還是Button

那個問題用htmlpage.executeJavaScript(script code)解決了,但最近遇到一個錯誤(用的是HtmlUnit 2.8): 

警告: Expected content type of 'application/javascript' or 'application/ecmascript' for remotely loaded JavaScript element at 'http://www.ibcbet.com/commjs/ieupdate.js', but got 'application/x-javascript'. 

似乎是個BUG,htmlunit作者承認的 22 樓  Foxswily 2011-03-10   看懂了HtmlUnit自然知道這種送出和普通按鈕沒什麼差別,僅僅在于你取的是Link還是Button 21 樓  alosin 2011-03-09   那想請問一下,如果遇到直接通過js将Form送出的,有沒有好的解決辦法 

比如:<a href="#" target="_blank" rel="external nofollow" click="return submit()"></a> 

還有沒搞清楚,為什麼HtmlForm沒有直接submit的方法。。。 20 樓  buaastorm 2010-12-03   第一個問題我最後通過getByValue解決了,第二個我也實在沒有辦法,一直沒弄明白HttpClient的機制,導緻老是連接配接不到伺服器。不過看到你的文章還是很受啟發,thx。 19 樓  Foxswily 2010-12-03   第一個問題,HtmlPage的方法getElementsByTagName(String tagName),按tag慢慢過濾,現在的頁面不帶id、name也夠少見了

第二個問題,HttpClient和HtmlUnit不是一個層次上的,HtmlUnit底層使用了HttpClient,他友善的地方在于Html和JS的解析。 18 樓  buaastorm 2010-12-02   對了,不知道你對HttpClient熟悉嗎?其實如果這個功能能用HttpClient來做的話,我更傾向于那個,我感覺那個的速度好像比HtmlUnit快。 17 樓  buaastorm 2010-12-02   我遇到了這麼一個網頁,沒有button的id,這個時候不知道該怎麼處理? 

Java代碼  

HtmlUnit實作的網站登入
  1. <form id="f_login" name="f_login" action="" target="_self" method="post" οnsubmit="return checkInput();">  
  2. <input type="hidden" name="redirect" value="http://www.nate.com">     
  3. <input type="hidden" id="PASSWD_RSA" name="PASSWD_RSA" value="">  
  4. <fieldset>  
  5.     <legend>로그인</legend>  
  6.     <dl>  
  7.         <dt>로그인</dt>  
  8.         <dd>  
  9.             <input type="text" id="ID" name="ID" class="bg_id" maxlength="25" οnclick="this.className='bg';" onKeyDown="this.className='bg';" tabindex="1" title="아이디 입력" οnfοcus="xXecure.showCKKeyProPopup();" οnblur="xXecure.hideCKKeyProPopup();" /> @  
  10.             <select id="domain" name="domain" tabindex="2"><!-- 2009.07 : ID 추가 -->  
  11.                 <option selected="selected">nate.com</option>  
  12.                 <option>empas.com</option>  
  13.                 <option>lycos.co.kr</option>  
  14.                 <option>netsgo.com</option>  
  15.             </select>  
  16.         </dd>  
  17.         <dd>  
  18.             <input type="password" id="PASSWD" name="PASSWD" class="bg_passwd" maxlength="20" οnclick="this.className='bg';" onKeyDown="this.className='bg';" tabindex="3" title="비밀번호 입력" οnkeypress="if (13 == event.keyCode) submit();" οnfοcus="xXecure.showCKKeyProPopup();" οnblur="xXecure.hideCKKeyProPopup();" enc="on" />  
  19.         </dd>  
  20.         <dd class="check">  
  21.             <input type="checkbox" id="saveid" name="saveid"  /> <label for="saveid" id="" tabindex="4">아이디 저장</label>  
  22.             <a class="btn_otp" οnclick="xXecurePop.openWin(2);" title="OTP보안 안내">OTP보안 안내</a>  
  23.         </dd>  
  24.         <dd class="btn">  
  25.             <input type="submit" tabindex="6" title="로그인버튼" value=""/>  
  26.         </dd>  
  27.     </dl>  
  28. </fieldset>  
  29. </form>  

底下這部分是用來送出這個form的 

Java代碼  

HtmlUnit實作的網站登入
  1. <input type="submit" tabindex="6" title="로그인버튼" value=""/>    

16 樓  twfy914 2010-06-08   不知道樓上的朋友看過那種批量注冊軟體沒? 

就是什麼126郵箱批量注冊之内的 

說白了就是把驗證碼直接顯示到軟體界面上去,然後留個輸入框讓你手工輸入,然後手工點送出,程式自動完成其他元素的填寫。明白? 15 樓  nighthawk 2010-05-17   wxy5001 寫道 Foxswily 寫道 驗證碼是所有類似工具都要面對的問題,我嘗試兩種方式解決 

1.圖像識别,這個可以單獨拿來研究了,算法難度不小,外加現在的圖檔幹擾越來越邪乎,不好實作。 

2.顯示圖檔人工解決,個人推薦這方式。畢竟登入一次可以程式保障長期線上,成本效益高的方案:)

第二個解決方法,能不能帖段代碼...

HtmlUnit實作的網站登入

1,把登陸頁面刷出來。 

2,肉眼識别出驗證碼。 

3,把驗證碼寫死到程式裡去。 

是不是這樣 14 樓  wxy5001 2010-05-17   Foxswily 寫道 驗證碼是所有類似工具都要面對的問題,我嘗試兩種方式解決 

1.圖像識别,這個可以單獨拿來研究了,算法難度不小,外加現在的圖檔幹擾越來越邪乎,不好實作。 

2.顯示圖檔人工解決,個人推薦這方式。畢竟登入一次可以程式保障長期線上,成本效益高的方案:)

第二個解決方法,能不能帖段代碼...

HtmlUnit實作的網站登入

13 樓  yangfuchao418 2010-04-19   樓主寫的不錯。入門了。 12 樓  Foxswily 2010-04-16   驗證碼是所有類似工具都要面對的問題,我嘗試兩種方式解決

1.圖像識别,這個可以單獨拿來研究了,算法難度不小,外加現在的圖檔幹擾越來越邪乎,不好實作。

2.顯示圖檔人工解決,個人推薦這方式。畢竟登入一次可以程式保障長期線上,成本效益高的方案:) 11 樓  whaosoft 2010-04-16   這個好使嗎 10 樓  srdrm 2010-04-16   樓上的問題提得好, 呵呵. 

這個貌似一個不錯的測試工具. 9 樓  xiaoyiz 2010-04-16   驗證碼怎麼辦? 8 樓  caoyangx 2010-04-16   我知道,謝謝。