HtmlUnit实现的网站登录

来源:互联网 发布:pos机小票打印软件 编辑:程序博客网 时间:2024/05/28 05:14

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代码  收藏代码
  1. //创建浏览器,可以选择IE、FF等等  
  2. WebClient client = new WebClient(BrowserVersion.INTERNET_EXPLORER_7);  
  3.   
  4. //获取某网站页面  
  5. HtmlPage page = client.getPage("http://xxx.com");  
  6.   
  7. //获取某页面元素,可通过id或name,(具体方式很多 --Foxswily)  
  8. HtmlElement elmt = page.getElementById("someid");  
  9. //HtmlElement elmt = page.getElementByName("somename");  
  10.   
  11. //此例以文本框为例,先点击,再输入,完全跟真浏览器行为一致  
  12. elmt.click();  
  13. elmt.type("somewords");  
  14.   
  15. //获取按钮  
  16. HtmlButton loginBtn = (HtmlButton)page.getElementById("btnId");  
  17. //点击并获得返回结果  
  18. Page resultPage = loginBtn.click();  
  19. //结果拿到了,想干啥您随意  
  20. 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代码  收藏代码
  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.   
  10.     final String refreshString = getRefreshStringOrNull();  
  11.     if (refreshString == null || refreshString.length() == 0) {  
  12.         return;  
  13.     }  
  14.   
  15.     final double time;  
  16.     final URL url;  
  17.   
  18.     int index = refreshString.indexOf(";");  
  19.     final boolean timeOnly = (index == -1);  
  20.   
  21.     if (timeOnly && refreshString.indexOf(" ") == -1) {  
  22.         // Format: <meta http-equiv='refresh' content='10'>  
  23.         try {  
  24.             time = Double.parseDouble(refreshString);  
  25.         } catch (final NumberFormatException e) {  
  26.             if (LOG.isErrorEnabled()) {  
  27.                 LOG.error("Malformed refresh string (no ';' but not a number): "  
  28.                         + refreshString, e);  
  29.             }  
  30.             return;  
  31.         }  
  32.         url = getWebResponse().getRequestSettings().getUrl();  
  33.     } else {  
  34.         if (refreshString.indexOf(";") == -1) {  
  35.             index = refreshString.indexOf(" ");  
  36.         }  
  37.         // Format: <meta http-equiv='refresh'  
  38.         // content='10;url=http://www.blah.com'>  
  39.         try {  
  40.             time = Double.parseDouble(refreshString.substring(0, index).trim());  
  41.         } catch (final NumberFormatException e) {  
  42.             if (LOG.isErrorEnabled()) {  
  43.                 LOG.error("Malformed refresh string (no valid number before ';') "  
  44.                         + refreshString, e);  
  45.             }  
  46.             return;  
  47.         }  
  48.         index = refreshString.toLowerCase().indexOf("url=", index);  
  49.         if (index == -1) {  
  50.             if (LOG.isErrorEnabled()) {  
  51.                 LOG.error("Malformed refresh string (found ';' but no 'url='): "  
  52.                         + refreshString);  
  53.             }  
  54.             return;  
  55.         }  
  56.         final StringBuilder buffer = new StringBuilder(refreshString  
  57.                 .substring(index + 4));  
  58.         if (buffer.toString().trim().length() == 0) {  
  59.             // content='10; URL=' is treated as content='10'  
  60.             url = getWebResponse().getRequestSettings().getUrl();  
  61.         } else {  
  62.             if (buffer.charAt(0) == '"' || buffer.charAt(0) == 0x27) {  
  63.                 buffer.deleteCharAt(0);  
  64.             }  
  65.             if (buffer.charAt(buffer.length() - 1) == '"'  
  66.                     || buffer.charAt(buffer.length() - 1) == 0x27) {  
  67.                 buffer.deleteCharAt(buffer.length() - 1);  
  68.             }  
  69.             final String urlString = buffer.toString();  
  70.             try {  
  71.                 url = getFullyQualifiedUrl(urlString);  
  72.             } catch (final MalformedURLException e) {  
  73.                 if (LOG.isErrorEnabled()) {  
  74.                     LOG.error("Malformed URL in refresh string: " + refreshString, e);  
  75.                 }  
  76.                 throw e;  
  77.             }  
  78.         }  
  79.     }  
  80.   
  81.     final int timeRounded = (int) time;  
  82.     getWebClient().getRefreshHandler().handleRefresh(this, url, timeRounded);  
  83. }  
 




分享到:  
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,*" border="0px" frameborder="0" framespacing="0px" >  
  <frame src="blank.jsp" scrolling="no" noresize> 
  <frameset rows="90,*" cols="*" frameborder="NO" border="0" framespacing="0"> 
    <frame src="header.jsp" rows="90,*" scrolling="no" noresize name="header"  > 
    <frameset cols="200,*" frameborder="NO" border="0" 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="#" 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代码  收藏代码
  1. <form id="f_login" name="f_login" action="" target="_self" method="post" onsubmit="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" onclick="this.className='bg';" onKeyDown="this.className='bg';" tabindex="1" title="아이디 입력" onfocus="xXecure.showCKKeyProPopup();" onblur="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" onclick="this.className='bg';" onKeyDown="this.className='bg';" tabindex="3" title="비밀번호 입력" onkeypress="if (13 == event.keyCode) submit();" onfocus="xXecure.showCKKeyProPopup();" onblur="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" onclick="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代码  收藏代码
  1. <input type="submit" tabindex="6" title="로그인버튼" value=""/>    
16 楼 twfy914 2010-06-08  
不知道楼上的朋友看过那种批量注册软件没? 
就是什么126邮箱批量注册之内的 
说白了就是把验证码直接显示到软件界面上去,然后留个输入框让你手工输入,然后手工点提交,程序自动完成其他元素的填写。明白?
15 楼 nighthawk 2010-05-17  
wxy5001 写道
Foxswily 写道
验证码是所有类似工具都要面对的问题,我尝试两种方式解决 
1.图像识别,这个可以单独拿来研究了,算法难度不小,外加现在的图片干扰越来越邪乎,不好实现。 
2.显示图片人工解决,个人推荐这方式。毕竟登录一次可以程序保障长期在线,性价比高的方案:)



第二个解决方法,能不能帖段代码...

1,把登陆页面刷出来。 
2,肉眼识别出验证码。 
3,把验证码写死到程序里去。 
是不是这样
14 楼 wxy5001 2010-05-17  
Foxswily 写道
验证码是所有类似工具都要面对的问题,我尝试两种方式解决 
1.图像识别,这个可以单独拿来研究了,算法难度不小,外加现在的图片干扰越来越邪乎,不好实现。 
2.显示图片人工解决,个人推荐这方式。毕竟登录一次可以程序保障长期在线,性价比高的方案:)



第二个解决方法,能不能帖段代码...
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  
我知道,谢谢。

0 0