如何用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
相关产品推荐
相关产品推荐

