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代碼
- //建立浏覽器,可以選擇IE、FF等等
- WebClient client = new WebClient(BrowserVersion.INTERNET_EXPLORER_7);
- //擷取某網站頁面
- HtmlPage page = client.getPage("http://xxx.com");
- //擷取某頁面元素,可通過id或name,(具體方式很多 --Foxswily)
- HtmlElement elmt = page.getElementById("someid");
- //HtmlElement elmt = page.getElementByName("somename");
- //此例以文本框為例,先點選,再輸入,完全跟真浏覽器行為一緻
- elmt.click();
- elmt.type("somewords");
- //擷取按鈕
- HtmlButton loginBtn = (HtmlButton)page.getElementById("btnId");
- //點選并獲得傳回結果
- Page resultPage = loginBtn.click();
- //結果拿到了,想幹啥您随意
- 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代碼
- private void executeRefreshIfNeeded() throws IOException {
- // If this page is not in a frame then a refresh has already happened,
- // most likely through the JavaScript onload handler, so we don't do a
- // second refresh.
- final WebWindow window = getEnclosingWindow();
- if (window == null) {
- return;
- }
- final String refreshString = getRefreshStringOrNull();
- if (refreshString == null || refreshString.length() == 0) {
- return;
- }
- final double time;
- final URL url;
- int index = refreshString.indexOf(";");
- final boolean timeOnly = (index == -1);
- if (timeOnly && refreshString.indexOf(" ") == -1) {
- // Format: <meta http-equiv='refresh' content='10'>
- try {
- time = Double.parseDouble(refreshString);
- } catch (final NumberFormatException e) {
- if (LOG.isErrorEnabled()) {
- LOG.error("Malformed refresh string (no ';' but not a number): "
- + refreshString, e);
- }
- return;
- }
- url = getWebResponse().getRequestSettings().getUrl();
- } else {
- if (refreshString.indexOf(";") == -1) {
- index = refreshString.indexOf(" ");
- }
- // Format: <meta http-equiv='refresh'
- // content='10;url=http://www.blah.com'>
- try {
- time = Double.parseDouble(refreshString.substring(0, index).trim());
- } catch (final NumberFormatException e) {
- if (LOG.isErrorEnabled()) {
- LOG.error("Malformed refresh string (no valid number before ';') "
- + refreshString, e);
- }
- return;
- }
- index = refreshString.toLowerCase().indexOf("url=", index);
- if (index == -1) {
- if (LOG.isErrorEnabled()) {
- LOG.error("Malformed refresh string (found ';' but no 'url='): "
- + refreshString);
- }
- return;
- }
- final StringBuilder buffer = new StringBuilder(refreshString
- .substring(index + 4));
- if (buffer.toString().trim().length() == 0) {
- // content='10; URL=' is treated as content='10'
- url = getWebResponse().getRequestSettings().getUrl();
- } else {
- if (buffer.charAt(0) == '"' || buffer.charAt(0) == 0x27) {
- buffer.deleteCharAt(0);
- }
- if (buffer.charAt(buffer.length() - 1) == '"'
- || buffer.charAt(buffer.length() - 1) == 0x27) {
- buffer.deleteCharAt(buffer.length() - 1);
- }
- final String urlString = buffer.toString();
- try {
- url = getFullyQualifiedUrl(urlString);
- } catch (final MalformedURLException e) {
- if (LOG.isErrorEnabled()) {
- LOG.error("Malformed URL in refresh string: " + refreshString, e);
- }
- throw e;
- }
- }
- }
- final int timeRounded = (int) time;
- getWebClient().getRefreshHandler().handleRefresh(this, url, timeRounded);
- }
分享到:
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代碼
- <form id="f_login" name="f_login" action="" target="_self" method="post" οnsubmit="return checkInput();">
- <input type="hidden" name="redirect" value="http://www.nate.com">
- <input type="hidden" id="PASSWD_RSA" name="PASSWD_RSA" value="">
- <fieldset>
- <legend>로그인</legend>
- <dl>
- <dt>로그인</dt>
- <dd>
- <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();" /> @
- <select id="domain" name="domain" tabindex="2"><!-- 2009.07 : ID 추가 -->
- <option selected="selected">nate.com</option>
- <option>empas.com</option>
- <option>lycos.co.kr</option>
- <option>netsgo.com</option>
- </select>
- </dd>
- <dd>
- <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" />
- </dd>
- <dd class="check">
- <input type="checkbox" id="saveid" name="saveid" /> <label for="saveid" id="" tabindex="4">아이디 저장</label>
- <a class="btn_otp" οnclick="xXecurePop.openWin(2);" title="OTP보안 안내">OTP보안 안내</a>
- </dd>
- <dd class="btn">
- <input type="submit" tabindex="6" title="로그인버튼" value=""/>
- </dd>
- </dl>
- </fieldset>
- </form>
底下這部分是用來送出這個form的
Java代碼
- <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 我知道,謝謝。