1.HtmlUnit簡要介紹
HtmlUnit是一款java的無界面瀏覽器程序庫。它模擬HTML文檔,並提供相應的API,允許您調用頁面,填寫表單,點擊鏈接等操作,就像您在“正常”瀏覽器中做的一樣。它有相當不錯的JavaScript支持(還在不斷改進),甚至能夠處理相當復雜的AJAX庫,模擬Chrome,Firefox或Internet Explorer取決於使用的配置。它通常用於測試目的或從網站檢索信息。
HtmlUnit不是一個通用的單元測試框架。它是一種模擬瀏覽器以用於測試目的的方法,並且旨在用於另一個測試框架(如JUnit或TestNG)中。有關簡介,請參閱文檔“HtmlUnit入門”。HtmlUnit用作不同的開源工具,如Canoo WebTest,JWebUnit,WebDriver,JSFUnit,WETATOR,Celerity,Spring MVC Test HtmlUnit作為底層的“瀏覽器”。
HtmlUnit最初由Gargoyle Software的Mike Bowler編寫,並根據Apache 2許可證發布。從那時起,它已經收到了許多來自其他開發商的貢獻,今天也會得到他們的幫助。
幾年前在做一個購物網站的數據抓取工作中,偶然的機會邂逅了HtmlUnit了。記得當時怎么也捉取不到頁面上的價格數據,而httpfox也追蹤不到價格數據的URL,正當我一愁莫展的時個,HtmlUnit出現並幫我解決了問題。所以今天我要說聲謝謝,也將HtmlUnit推薦給大家。
2.htmlUnit中文文檔
3.1 獲取頁面的TITLE、XML代碼、文本
import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.BrowserVersion; import com.gargoylesoftware.htmlunit.html.HtmlDivision; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; import com.gargoylesoftware.htmlunit.*; import com.gargoylesoftware.htmlunit.WebClientOptions; import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlBody; import java.util.List; public class helloHtmlUnit{ public static void main(String[] args) throws Exception{ String str; //創建一個webclient WebClient webClient = new WebClient(); //htmlunit 對css和javascript的支持不好,所以請關閉之 webClient.getOptions().setJavaScriptEnabled(false); webClient.getOptions().setCssEnabled(false); //獲取頁面 HtmlPage page = webClient.getPage("http://www.baidu.com/"); //獲取頁面的TITLE str = page.getTitleText(); System.out.println(str); //獲取頁面的XML代碼 str = page.asXml(); System.out.println(str); //獲取頁面的文本 str = page.asText(); System.out.println(str); //關閉webclient webClient.closeAllWindows(); } }
3.2 使用不同版本的瀏覽器打開
import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.BrowserVersion; import com.gargoylesoftware.htmlunit.html.HtmlDivision; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; import com.gargoylesoftware.htmlunit.*; import com.gargoylesoftware.htmlunit.WebClientOptions; import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlBody; import java.util.List; public class helloHtmlUnit{ public static void main(String[] args) throws Exception{ String str; //使用FireFox讀取網頁 WebClient webClient = new WebClient(BrowserVersion.FIREFOX_24); //htmlunit 對css和javascript的支持不好,所以請關閉之 webClient.getOptions().setJavaScriptEnabled(false); webClient.getOptions().setCssEnabled(false); HtmlPage page = webClient.getPage("http://www.baidu.com/"); str = page.getTitleText(); System.out.println(str); //關閉webclient webClient.closeAllWindows(); } }
3.3 找到頁面中特定的元素
public class helloHtmlUnit{ public static void main(String[] args) throws Exception{ //創建webclient WebClient webClient = new WebClient(BrowserVersion.CHROME); //htmlunit 對css和javascript的支持不好,所以請關閉之 webClient.getOptions().setJavaScriptEnabled(false); webClient.getOptions().setCssEnabled(false); HtmlPage page = (HtmlPage)webClient.getPage("http://www.baidu.com/"); //通過id獲得"百度一下"按鈕 HtmlInput btn = (HtmlInput)page.getHtmlElementById("su"); System.out.println(btn.getDefaultValue()); //關閉webclient webClient.closeAllWindows(); } }
tips:有些元素中沒有id和name或其他節點,可以通過找他的子節點和父節點之間規律的方法來獲取該元素,具體方法參考:https://blog.csdn.net/qq_36237061/article/details/86533278
其核心代碼為:
final HtmlPage nextPage = ((DomElement)(htmlpage.getElementByName("key").getParentNode().getParentNode())).getLastElementChild().click();
3.4 元素檢索
public class helloHtmlUnit{ public static void main(String[] args) throws Exception{ //創建webclient WebClient webClient = new WebClient(BrowserVersion.CHROME); //htmlunit 對css和javascript的支持不好,所以請關閉之 webClient.getOptions().setJavaScriptEnabled(false); webClient.getOptions().setCssEnabled(false); HtmlPage page = (HtmlPage)webClient.getPage("http://www.baidu.com/"); //查找所有div List<?> hbList = page.getByXPath("//div"); HtmlDivision hb = (HtmlDivision)hbList.get(0); System.out.println(hb.toString()); //查找並獲取特定input List<?> inputList = page.getByXPath("//input[@id='su']"); HtmlInput input = (HtmlInput)inputList.get(0); System.out.println(input.toString()); //關閉webclient webClient.closeAllWindows(); } }
3.5 提交搜索
public class helloHtmlUnit{ public static void main(String[] args) throws Exception{ //創建webclient WebClient webClient = new WebClient(BrowserVersion.CHROME); //htmlunit 對css和javascript的支持不好,所以請關閉之 webClient.getOptions().setJavaScriptEnabled(false); webClient.getOptions().setCssEnabled(false); HtmlPage page = (HtmlPage)webClient.getPage("http://www.baidu.com/"); //獲取搜索輸入框並提交搜索內容 HtmlInput input = (HtmlInput)page.getHtmlElementById("kw"); System.out.println(input.toString()); input.setValueAttribute("ymd"); System.out.println(input.toString()); //獲取搜索按鈕並點擊 HtmlInput btn = (HtmlInput)page.getHtmlElementById("su"); HtmlPage page2 = btn.click(); //輸出新頁面的文本 System.out.println(page2.asText()); } }
3.htmlUnit方法介紹
一、環境引入
因為我是在我自己的spring boot項目在引入的,所以我在pom文件中加入依賴就行了
<dependency> <groupId>net.sourceforge.htmlunit</groupId> <artifactId>htmlunit</artifactId> <version>2.41.0</version> </dependency>
如果你只是爬取一個js不多的網站我建議換下面這個依賴
<dependency> <groupId>net.sourceforge.htmlunit</groupId> <artifactId>htmlunit</artifactId> <version>2.23</version> </dependency>
兩者的區別我后面會講,當然如果你不是用的maven工程(沒有pom),可以去官網下載源代碼庫
二、使用
HtmlUnit使用起來非常簡單,在使用時可以去官網手冊查看語法事實上手冊僅僅是入門講解,聽我下面講也夠了;
1、創建客戶端和配置客戶端
final String url ="https:****";//大家這可以填自己爬蟲的地址 WebClient webClient = new WebClient(BrowserVersion.FIREFOX_68);//創建火狐瀏覽器 2.23版本是FIREFOX_45 new不寫參數是默認瀏覽器 webClient.getOptions().setCssEnabled(false);//(屏蔽)css 因為css並不影響我們抓取數據 反而影響網頁渲染效率 webClient.getOptions().setThrowExceptionOnScriptError(false);//(屏蔽)異常 webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);//(屏蔽)日志 webClient.getOptions().setJavaScriptEnabled(true);//加載js腳本 webClient.getOptions().setTimeout(50000);//設置超時時間 webClient.setAjaxController(new NicelyResynchronizingAjaxController());//設置ajax HtmlPage htmlPage = webClient.getPage(url);//將客戶端獲取的樹形結構轉化為HtmlPage Thread.sleep(10000);//主線程休眠10秒 讓客戶端有時間執行js代碼 也可以寫成webClient.waitForBackgroundJavaScript(1000)
這里有個等待js執行,2.41.0很好兼容js多的情況,2.3卻老是出問題,無法刷新網頁,2.41.0打印的也很詳細,執行過程也比較慢,可能慢工出細活
這里差多就獲取了遠程地址頁面,現在要做的就是解析dom節點 填寫數據模擬點擊等事件。如果你要將他打印輸出 htmlPage.asText()輸出htmlPage節點的文本 htmlPage.asXml()輸出htmlPage節點的xml代碼
2、節點的獲取
在此環節建議預備一點前端的知識
HtmlUnit給出兩種節點獲取方式
XPath查詢:
比較詳細的xpath講解:https://testerhome.com/topics/20296
final HtmlPage page = webClient.getPage("http://htmlunit.sourceforge.net"); //get list of all divs final List<?> divs = htmlPage .getByXPath("//div"); //get div which has a 'name' attribute of 'John' final HtmlDivision div = (HtmlDivision) htmlPage .getByXPath("//div[@name='John']").get(0);
css選擇器:(我更加鍾愛)
final DomNodeList<DomNode> divs = htmlPage .querySelectorAll("div"); for (DomNode div : divs) { .... } //get div which has the id 'breadcrumbs' final DomNode div = htmlPage .querySelector("div#breadcrumbs");
css給出集合查詢querySelectorAll和單個查詢querySelector,如果你沒有基礎我給出以下例子你就明白:
htmlPage .querySelectorAll(“div”)返回htmlPage下面div標簽集合
htmlPage .querySelector(“div:nth-child(1)”)返回htmlPage下面div的第一個div
htmlPage .querySelector(".submit")返回htmlPage下面第一個class=submit的標簽
htmlPage .querySelector("#submit")返回htmlPage下面第一個id=submit的標簽
htmlPage .querySelector(“div.submit”)返回htmlPage下面第一個class為submit的div標簽
htmlPage .querySelector(“div[id=‘submit’]”)返回htmlPage下面第一個id為submit的div標簽
以上的列舉方法相信已經夠用,不夠的可以參閱css選擇器
以下列舉常見的html標簽與HtmlUnit類的對應關系
div -> HtmlDivision div集合 -> DomNodeList<DomNode> fieldSet -> HtmlFieldSet form -> HtmlForm button -> HtmlButton a -> HtmlAnchor <input type="xxx"> -> HtmlXxxInput (<input type="text"> -> HtmlTextInput) table -> HtmlTable tr -> HtmlTableRow td -> TableDataCell
有 setAttribute()方法節點的屬性樣式,setNodeValue()設置節點value值。是不是英語一下子就提高了?幾乎所有的標簽可以找到與之對應的的類,下面看我的實戰:這是一個在線填寫溫度的excel文檔 如果訪問改地址,他會提示登陸網頁上有登錄按鈕,如果登錄過網頁上是沒有登錄按鈕,我們現在模擬打開自動登錄框:
//這段代碼是為了讓網頁的的某個按鈕加載出來之后再執行下面的代碼 while (htmlPage.querySelector("#header-login-btn")==null) { synchronized (htmlPage) { htmlPage.wait(1000); } } HtmlButton login = htmlPage.querySelector("#header-login-btn");//獲取到登陸按鈕 if (login!=null){//如果網頁上沒這個按鈕你還要去獲取他只會得到一個空對象,所以我們用空的方式可以判斷網頁上是否有這個按鈕 System.out.println("-----未登錄測試-----"); htmlPage=login.click();//模擬按鈕點擊后要將網頁返回回來方便動態更新數據 System.out.println(htmlPage.asText()); HtmlAnchor switcher_plogin = htmlPage.querySelector("a[id='switcher_plogin']"); if (switcher_plogin!=null) {//帳號密碼登錄 System.out.println("-----點擊了帳號密碼登陸-----"); htmlPage = switcher_plogin.click(); System.out.println(htmlPage.asText()); } } System.out.println(htmlPage.asText()); webClient.close();
爬蟲最重要的步驟是我們對網頁先進行調試,有哪些按鈕,要點擊哪個,要給哪些設值。畢竟我們要用代碼安排代碼。
**延申:**如果你要對網頁的數據獲取或者文件進行下載,光靠HtmlUnit解析是不夠的,推薦Jsoup庫,是可以配合HtmlUnit使用的,比較好用,這里就不列舉。
三、實現一個小的demo
注意:htmlunit引用的jar包不全是會奇怪的報錯
使用maven方法比較方便
參考:https://blog.csdn.net/weixin_44787678/article/details/106994485