首页 > 编程语言 >HtmlUnit:自动化操作web页面的java工具

HtmlUnit:自动化操作web页面的java工具

时间:2024-08-22 22:05:52浏览次数:9  
标签:web java htmlunit gargoylesoftware import 页面 com webClient HtmlUnit

java有httpclient等工具,可以模拟进行一些web操作,但一些逻辑是在前端js中执行的,此时httpclient就比较困难了。

此时可以考虑使用HtmlUnit,模拟出一个浏览器,全程在浏览器中操作。

 

本文以 在百度中输入搜索关键字->点击“百度一下” 按钮->打印搜索结果 这一过程为例,演示HtmlUnit的使用

 

首先,我们要把上面的过程再代码化一点,F12打开开发者工具,检查发现输入框的id是kw,查询按钮的id是su。

而点击查询后,查询结果是写在这样的div里:

<div  data-tools="{'title': &quot;xxx技术博客_51CTO博客&quot;,'url': xxx;}" aria-hidden="true"></div>

 

因此,上述过程可以描述为

1、打开百度首页

2、查找id为kw的元素,写入查询关键字

3、查找id为su的元素,点击它

4、在页面中查找div标签并打印data-tools属性。

 

依照此过程,我们就开始写代码了:

引入maven依赖

        <dependency>
            <groupId>net.sourceforge.htmlunit</groupId>
            <artifactId>htmlunit</artifactId>
            <version>2.60.0</version>
        </dependency>

按流程写代码

package org.example;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
import com.gargoylesoftware.htmlunit.util.Cookie;
import org.apache.commons.lang3.StringUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        // 创建一个模拟 Chrome 浏览器的 WebClient 实例
        final WebClient webClient = new WebClient(BrowserVersion.CHROME);

        // 配置 WebClient
        webClient.getOptions().setThrowExceptionOnScriptError(false);//当JS执行出错的时候是否抛出异常, 这里选择不需要
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);//当HTTP的状态非200时是否抛出异常, 这里选择不需要
        webClient.getOptions().setActiveXNative(false);
        webClient.getOptions().setCssEnabled(false);//是否启用CSS, 因为不需要展现页面, 所以不需要启用
        webClient.getOptions().setJavaScriptEnabled(true); //很重要,启用JS
        webClient.setAjaxController(new NicelyResynchronizingAjaxController());//很重要,设置支持AJAX

        HtmlPage page = null;
        try {
            // 访问百度主页
            page = webClient.getPage("https://www.baidu.com/");


            // 找到搜索输入框
            HtmlTextInput textField;
            do {
                textField = (HtmlTextInput) page.getElementById("kw");
                if (null != textField) {
                    break;
                }
                // 未找到说明页面还没加载完,继续等待页面加载完成
                webClient.waitForBackgroundJavaScript(1000);
            } while (true);

            // 输入查询文本
            textField.setValueAttribute("HtmlUnit自动测试");
            // 找到提交按钮并点击
            HtmlSubmitInput button = (HtmlSubmitInput) page.getElementById("su");
            page = button.click();

            //解析页面结果 这里如果百度的页面改了,需要做相应的调整
            List<String> res = new LinkedList<>();
            do {
                // 等待异步 JS 执行完成
                webClient.waitForBackgroundJavaScript(1000);
                // 提取结果页面中的<div data-tools="{'title': xxx">元素,也就是百度的检索结果关键元素
                for (DomElement div : page.getElementsByTagName("div")) {
                    String text = div.getAttribute("data-tools");
                    if (StringUtils.isNotBlank(text)) {
                        res.add(text);
                    }
                }
            } while (res.isEmpty());//res非空说明解析到结果了

            for (String s : res) {
                System.out.println(s);
            }


            System.out.println("--------------------------------------------------");
            // 获取并打印 cookies
            Set<Cookie> cookies = webClient.getCookieManager().getCookies();
            System.out.println("Cookies:");
            for (Cookie cookie : cookies) {
                System.out.println("Name: " + cookie.getName() + ", Value: " + cookie.getValue());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            webClient.close();
        }
    }


}

运行得到结果。

 

最后提醒,本文只是以此为例介绍HtmlUnit的使用,请读者在应用中注意遵纪守法,各网站基本都有反爬虫机制,爬虫写得好,牢饭吃到饱。HtmlUnit更应该用到页面自动化测试等场景,而不是打擦边球去写爬虫。

标签:web,java,htmlunit,gargoylesoftware,import,页面,com,webClient,HtmlUnit
From: https://www.cnblogs.com/imliuyu/p/18374846

相关文章

  • Javaweb+jsp外卖点餐系统+源码(三)
    第三章详细设计3.1 用户的主界面用户的主菜单界面。页面如图3-1所示:图3-1 用户的主界面3.2用户注册页面用户在首次登录外卖订餐系统管理页面时,需要在注册页面需要完成个人信息的注册。页面如图3-2所示:图3-2外卖订餐系统的注册页面3.3用户登录界面用户通......
  • 为什么java找工作难?java饱和了吗?
    在开始前我有一些资料,是我根据网友给的问题精心整理了一份「java的资料从专业入门到高级学习路线规划图」提升技术才是王道!限于文章篇幅原因,就不一一展示了,有需要的小伙伴扫码添加小助理获取!!24年初,当下java程序员的需求情况是,零项目经验的求职者难找工作,只能证明自己做过增......
  • JavaScript 的 标签
    标签标签在JavaScript中不是一个常见的特性,但在某些情况下,它们可以用于改善循环的可读性或退出嵌套循环。//使用标签来标识循环loop1:for(leti=0;i<10;i++){//循环1loop2:for(letj=0;j<10;j++){//循环2if(i===2&&j===2){......
  • WebAPI中写单元测试
    首次在WebAPI中写单元测试xUnit这次我使用的是xUnit测试框架,而不是VS自带的MSTest框架。在添加新建项目时选择xUnit测试项目就行了。目前只体验到了一个差别,即xUnit可以使用特性向测试方法传参,而不用在测试方法中一个赋值语句一个个去定义参数,这是比较方便的。单元测试有一个......
  • JAVA IO流-小白版
    I/O流原理I/O是Input/Output的缩写,I/O流技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等;Java中对于数据的输入/输出操作以"流(stream)"的方式进行;Java.io包下提供了各种"流"类和接口,用以获取不同种类的数据,并通过方法输入或输出数据;输入input:读取外部......
  • ubuntu18安装novnc实现web远程桌面
    1.安装基础软件sudoaptinstall-ygit 2.下载novncsudogitclonegit://github.com/kanaka/noVNC/opt/novnc 3.修改权限sudochown-R$USER:$USER/opt/novnc 4.安装并运行vnc服务sudoaptinstall-ytightvncserversudovncserver 5.生成证书......
  • 深入理解 Java 中 ArrayList 的底层原理
    在这篇博客中,我们将深入探讨ArrayList的底层实现原理,并通过逐步剖析ArrayList的源码来理解其内部工作机制。我们将重点关注ArrayList的创建、元素添加、扩容机制等关键点。创建ArrayList集合对象ArrayList<String>list=newArrayList<>();使用空参构造器创建ArrayList集合......
  • [Java手撕]线程安全的转账
    首先来看线程不安全的转账publicclassBank{privateint[]accounts;publicBank(){this.accounts=newint[10];for(inti=0;i<10;i++){accounts[i]=1000;}}publicvoidtransfer(intfrom,int......
  • 一起学Java(3)-Java项目构建工具Gradle和Maven场景定位和优缺点对比
    在第一步创建的项目(java-all-in-one)项目里,我们提到了使用Gradle作为项目构建工具。看到这里,不知道你是否有疑惑,什么是项目构建工具。Java项目常用构建工具有哪些?都有什么特点?带着疑惑,本文对Java的构建工具进行一些梳理,以同步理解。从而使大家对我们项目中使用到的技术栈和技术......
  • Java多态
    1.多态1.1多态的概述(记忆)什么是多态不同类的对象在调用同一个方法时表现出来的多种不同行为多态的前提要有继承或实现关系要有方法的重写要有父类引用指向子类对象代码演示classAnimal{  publicvoideat(){    System.out.println("动物吃肉")......