htmlunit抓取动态网页(1.HtmlUnit中文文档获取页面中特定的元素tips:1.)
优采云 发布时间: 2022-02-18 07:14htmlunit抓取动态网页(1.HtmlUnit中文文档获取页面中特定的元素tips:1.)
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();
}
}
提示:有些元素没有 id 和 name 或其他节点。您可以通过查找其子节点和父节点之间的规律性来获取该元素。具体方法请参考:
它的核心代码是:
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文件中添加依赖即可
net.sourceforge.htmlunit
htmlunit
2.41.0
如果只是爬一点js 网站 建议改一下下面的依赖
net.sourceforge.htmlunit
htmlunit
2.23
两者的区别将在后面讨论。当然,如果你用的不是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解释:
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 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下第一个带有submit类的div标签
htmlPage.querySelector("div[id='submit']") 返回 htmlPage 下面的第一个 div 标签,id 为 submit
上面的枚举方式相信就够了,如果还不够,可以参考css选择器
下面列出了常见的html标签和HtmlUnit类的对应关系
div -> HtmlDivision
div集合 -> DomNodeList
fieldSet -> HtmlFieldSet
form -> HtmlForm
button -> HtmlButton
a -> HtmlAnchor
-> HtmlXxxInput
( -> HtmlTextInput)
table -> HtmlTable
tr -> HtmlTableRow
td -> TableDataCell
节点的属性样式有一个setAttribute()方法,setNodeValue()设置节点值。你的英语突然提高了吗?几乎所有的标签都能找到对应的类。来看看我的实战:这是一个在线填写温度的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方法更方便
参考: