You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用HtmlUnit下载文件?目标按钮无可用href/onclick属性

解决HtmlUnit点击无href/onclick按钮的文件下载问题

我来帮你搞定这个问题!这种没有直接href或onclick属性的下载按钮确实容易坑到新手——它的下载逻辑完全靠JavaScript动态触发,HtmlUnit默认的处理方式根本跟不上。咱们一步步来修正你的代码:

问题根源分析

你当前的代码里,点击下载按钮后直接把返回的HtmlPage转成UnexpectedPage,这是错误的逻辑:这个按钮点击后并不会返回一个HTML页面,而是浏览器收到了带有Content-Disposition: attachment头的响应,触发文件下载。HtmlUnit需要专门配置才能捕获这种下载请求。

解决方案步骤

1. 给WebClient配置下载处理器

首先要给你的WebClient设置一个自定义DownloadHandler,这样当下载请求发生时,我们能直接捕获到响应流并处理:

webClient.setDownloadHandler(new DownloadHandler() {
    @Override
    public void handleDownload(Page page, WebResponse response) throws IOException {
        // 从响应头解析文件名(如果有的话)
        String fileName = response.getResponseHeaderValue("Content-Disposition");
        if (fileName != null) {
            fileName = fileName.replaceFirst("(?i)^attachment; filename=\"?([^\"]+)\"?$", "$1");
        } else {
            fileName = "satellite_image.tif.gz";
        }

        // 读取GZIP流并保存到文件
        try (GZIPInputStream gzipIn = new GZIPInputStream(response.getContentAsStream());
             FileOutputStream out = new FileOutputStream(fileName)) {
            
            byte[] buffer = new byte[2048];
            int len;
            while ((len = gzipIn.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }

            // 更新Swing UI提示下载完成
            SwingUtilities.invokeLater(() -> reportLabel.setText("下载完成:" + fileName));
        } catch (IOException e) {
            SwingUtilities.invokeLater(() -> reportLabel.setText("下载失败:" + e.getMessage()));
            e.printStackTrace();
        }
    }
});

2. 补充WebClient的必要配置

确保WebClient启用了JavaScript、重定向处理等关键功能,避免JS执行不完整或请求被拦截:

// 启用JavaScript(默认开启,但明确设置更保险)
webClient.getOptions().setJavaScriptEnabled(true);
// 设置JS执行超时时间(防止无限等待)
webClient.getOptions().setJavaScriptTimeout(10000);
// 允许自动重定向(下载请求可能会有跳转)
webClient.getOptions().setRedirectEnabled(true);
// 忽略SSL证书错误(如果目标网站有证书问题)
webClient.getOptions().setUseInsecureSSL(true);

3. 修正下载按钮的点击逻辑

点击下载按钮后,不需要再获取返回的HtmlPage,只需要等待JavaScript完成下载请求的触发即可:

// 获取下载按钮并点击
HtmlButton ETButton = page2.getHtmlElementById("eta_download");
ETButton.click();

// 等待JS任务完成,确保下载请求被正确触发
JavaScriptJobManager manager = page2.getEnclosingWindow().getJobManager();
int waitCount = 0;
while (manager.getJobCount() > 0 && waitCount < 20) { // 最多等待10秒
    Thread.sleep(500);
    waitCount++;
    final int currentWait = waitCount;
    SwingUtilities.invokeLater(() -> reportLabel.setText("等待下载处理中... (" + currentWait + "/20)"));
}

完整关键代码整合

把以上修改整合到你的原有代码中,核心部分大概是这样:

// 创建浏览器实例
final WebClient webClient = new WebClient(BrowserVersion.CHROME);

// 配置下载处理器
webClient.setDownloadHandler(new DownloadHandler() {
    @Override
    public void handleDownload(Page page, WebResponse response) throws IOException {
        // 解析文件名
        String fileName = response.getResponseHeaderValue("Content-Disposition");
        if (fileName != null) {
            fileName = fileName.replaceFirst("(?i)^attachment; filename=\"?([^\"]+)\"?$", "$1");
        } else {
            fileName = "satellite_image.tif.gz";
        }

        // 保存GZIP文件
        try (GZIPInputStream gzipIn = new GZIPInputStream(response.getContentAsStream());
             FileOutputStream out = new FileOutputStream(fileName)) {
            
            byte[] buffer = new byte[2048];
            int len;
            while ((len = gzipIn.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }

            SwingUtilities.invokeLater(() -> reportLabel.setText("下载完成:" + fileName));
        } catch (IOException e) {
            SwingUtilities.invokeLater(() -> reportLabel.setText("下载失败:" + e.getMessage()));
            e.printStackTrace();
        }
    }
});

// 配置WebClient基础参数
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setJavaScriptTimeout(10000);
webClient.getOptions().setRedirectEnabled(true);
webClient.getOptions().setUseInsecureSSL(true);

// ... 你的原有代码:加载页面、填充表单、点击搜索、选择区域等 ...

// 点击下载按钮并等待处理
HtmlButton ETButton = page2.getHtmlElementById("eta_download");
ETButton.click();

JavaScriptJobManager manager = page2.getEnclosingWindow().getJobManager();
int waitCount = 0;
while (manager.getJobCount() > 0 && waitCount < 20) {
    Thread.sleep(500);
    waitCount++;
    final int currentWait = waitCount;
    SwingUtilities.invokeLater(() -> reportLabel.setText("等待下载处理中... (" + currentWait + "/20)"));
}

内容的提问来源于stack exchange,提问作者Shadowed_Viel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:50:56