news 2026/7/2 7:42:21

从第三方渲染html页面中下载对应的图片

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从第三方渲染html页面中下载对应的图片

一:需求:查看发票详情需要跳转第三方页面,然后右键复制图片保存到本地。一个个下载太麻烦

最后是从html中获取图片元素转为字节流,下载压缩到同一个文件夹:

二:pom依赖

<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.17.2</version> </dependency>

三:压缩成zip文件

@PostMapping("/qrcodes") @ApiOperation("测试导票据图片") public ResponseEntity<byte[]> exportQrCodes(@RequestBody(required = false) InvoiceSummary invoiceSummary) { try { // 数据 byte[] zipData = exportQrCodesToZip(invoiceSummary); // 生成文件名(带时间戳) String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String fileName = "qrcodes_" + timestamp + ".zip"; String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()) .replaceAll("\\+", "%20"); // 返回文件流,浏览器会自动下载到默认下载文件夹 return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedFileName) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(zipData); } catch (Exception e) { return ResponseEntity.internalServerError().build(); } }

四:获取需要处理的列表

public byte[] exportQrCodesToZip(InvoiceSummary invoiceSummary) { // 查询所有有二维码的数据 //示例数据 Map<String,Object> map1 = invoiceSummaryService.selectInvoiceSummaryByIdByAPP(520541L); Map<String,Object> map2 = invoiceSummaryService.selectInvoiceSummaryByIdByAPP(568177L); List<Map<String,Object>> list=new ArrayList<>(); list.add(map1); list.add(map2); if (CollectionUtils.isEmpty(list)) { throw new RuntimeException("没有找到数据"); } System.err.println("开始导出,共{}张二维码"+ list.size()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (ZipOutputStream zos = new ZipOutputStream(baos)) { int successCount = 0; int failCount = 0; for (Map<String, Object> entity : list) { String pictureUrl = entity.get("pictureUrl").toString(); if (pictureUrl == null || pictureUrl.isEmpty()) { continue; } String fileName; try { // 1. 获取页面HTML String html = TestBillDownload.fetchPageHtml(pictureUrl); System.out.println("页面加载成功,HTML长度: " + html.length()); // 2. 从页面中提取正确的参数 String imageUrl = TestBillDownload.buildImageUrlFromPage(html); if (imageUrl != null && !imageUrl.isEmpty()) { System.out.println("构建图片URL成功: " + imageUrl); fileName = "bill_image_" + System.currentTimeMillis() + ".jpg"; } else { System.out.println("构建图片URL失败"); throw new ServiceException(""); } // 2. 获取图片byte[] byte[] imageBytes = TestBillDownload.fetchImageBytes(imageUrl); if (imageBytes != null && imageBytes.length > 0) { System.out.println("获取图片成功,大小: " + imageBytes.length + " 字节 (" + (imageBytes.length / 1024) + " KB)"); } // 添加到ZIP文件 ZipEntry entry = new ZipEntry(fileName); zos.putNextEntry(entry); zos.write(imageBytes); zos.closeEntry(); successCount++; if (successCount % 100 == 0) { System.err.println("已打包 {} 张" + successCount); } // 添加小延迟,避免请求过快 Thread.sleep(100); } catch (Exception e) { System.err.println("处理图片失败: " + pictureUrl + ", 错误: " + e.getMessage()); failCount++; // 继续处理下一张,不要中断整个流程 } } System.err.println("打包完成,成功 " + successCount + " 张,失败 " + failCount + " 张"); // 注意:return 要放在循环外面! return baos.toByteArray(); } catch (IOException e) { throw new RuntimeException(e); } }

五:工具类

public static String fetchPageHtml(String url) throws Exception { Request request = new Request.Builder() .url(url) .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8") .header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8") .header("Cache-Control", "no-cache") .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { throw new RuntimeException("页面加载失败: " + response.code()); } return response.body().string(); } }
public static String buildImageUrlFromPage(String html) { String ciphertext = null; String appId = null; String method = null; // 1. 提取 ciphertext Pattern cipherPattern = Pattern.compile( "var\\s+ciphertext\\s*=\\s*[\"']([^\"']+)[\"']", Pattern.CASE_INSENSITIVE ); Matcher cipherMatcher = cipherPattern.matcher(html); if (cipherMatcher.find()) { ciphertext = cipherMatcher.group(1); System.out.println("提取到 ciphertext: " + ciphertext); } else { System.out.println("未找到 ciphertext"); return null; } // 2. 提取 appId Pattern appIdPattern = Pattern.compile( "var\\s+appId\\s*=\\s*[\"']([^\"']+)[\"']", Pattern.CASE_INSENSITIVE ); Matcher appIdMatcher = appIdPattern.matcher(html); if (appIdMatcher.find()) { appId = appIdMatcher.group(1); System.out.println("提取到 appId: " + appId); } else { System.out.println("未找到 appId"); return null; } // 3. 提取 method Pattern methodPattern = Pattern.compile( "var\\s+method\\s*=\\s*[\"']([^\"']+)[\"']", Pattern.CASE_INSENSITIVE ); Matcher methodMatcher = methodPattern.matcher(html); if (methodMatcher.find()) { method = methodMatcher.group(1); System.out.println("提取到 method: " + method); } else { // method 可能没有定义,使用默认值 method = "DISPLAYH5"; System.out.println("未找到 method,使用默认值: " + method); } // 4. 构建图片URL String imageUrl = "http://211.159.155.25:8001/colleges-proxy/peripheral/queryBill/queryEbillImg.do" + "?ciphertext=" + ciphertext + "&appId=" + appId + "&method=" + method; return imageUrl; }
public static byte[] fetchImageBytes(String imageUrl) throws Exception { // 构建请求 Request request = new Request.Builder() .url(imageUrl) .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") .header("Referer", "http://211.159.155.25:8001/") .header("Accept", "image/webp,image/apng,image/*,*/*;q=0.8") .header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8") .header("Connection", "keep-alive") .build(); try (Response response = client.newCall(request).execute()) { // 检查响应状态 if (!response.isSuccessful()) { throw new RuntimeException("下载失败,HTTP状态码: " + response.code() + ", 消息: " + response.message()); } // 获取Content-Type(可选,用于验证) String contentType = response.header("Content-Type"); System.out.println("Content-Type: " + contentType); // 直接返回byte[] byte[] imageBytes = response.body().bytes(); System.out.println("实际获取大小: " + imageBytes.length + " 字节 (" + (imageBytes.length / 1024) + " KB)"); return imageBytes; } }

六:结果

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 7:40:10

告别模拟器:3步在Windows上安装Android应用的终极指南

告别模拟器&#xff1a;3步在Windows上安装Android应用的终极指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾经想在Windows电脑上运行Android应用&#x…

作者头像 李华
网站建设 2026/7/2 7:39:56

简单的无线练习

一。配置接口类型lsw1&#xff1a;[LSW1]vlan batch 10 20 100[LSW1-GigabitEthernet0/0/1]port link-type trunk [LSW1-GigabitEthernet0/0/1]port trunk allow-pass vlan 10 20 100[LSW1]port-group group-member GigabitEthernet 0/0/2 to GigabitEthernet 0/0/4 [LSW1-Gig…

作者头像 李华