package com.example; import java.awt.image.BufferedImage; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import javax.imageio.ImageIO; import net.sourceforge.tess4j.Tesseract; import net.sourceforge.tess4j.TesseractException; // ... 其他必要的导入 ... public class CaptchaOCR { // Tesseract data 路径 (tessdata 文件夹所在目录) // Windows 示例: "C:\\Program Files\\Tesseract-OCR\\tessdata" // Linux/macOS 示例: 通常不需要设置,Tess4J 会自动查找 private static final String TESSDATA_PATH = "F:\\tool\\Tesseract-OCR\\tessdata"; // 根据你的安装路径修改 /** * 下载验证码图片 * @param imageUrl 图片的完整 URL * @return 图片的 BufferedImage 对象 * @throws IOException 如果下载失败 */ public static BufferedImage downloadImage(String imageUrl) throws IOException { URL url = new URL(imageUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); // 添加 User-Agent 等必要的请求头,模拟浏览器 conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"); // ... 其他头 ... int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { try (InputStream is = conn.getInputStream()) { // 将输入流读取到字节数组,ImageIO 从字节数组读取更稳定 ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; // 缓冲区大小,可以调整 int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { baos.write(buffer, 0, bytesRead); } ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); BufferedImage image = ImageIO.read(bais); if (image == null) { throw new IOException("Failed to read image from stream. Check image format."); } return image; } } else { throw new IOException("Failed to download image. HTTP error code: " + responseCode); } } /** * 对验证码图片进行预处理 (基础示例:转灰度+二值化) * 这是最关键的部分,需要根据验证码样式调整 * @param originalImage 原始图片 * @return 预处理后的图片 */ public static BufferedImage preprocessImage(BufferedImage originalImage) { // TODO: 这里是图像预处理的重点,需要根据实际验证码样式进行调整和优化 // 基础处理:转灰度 -> 二值化 int width = originalImage.getWidth(); int height = originalImage.getHeight(); BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); grayImage.getGraphics().drawImage(originalImage, 0, 0, null); BufferedImage binaryImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); // 二值化阈值,可能需要调整 (0-255) int threshold = 128; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int gray = grayImage.getRaster().getSample(x, y, 0); if (gray < threshold) { binaryImage.getRaster().setSample(x, y, 0, 0); // 黑色 } else { binaryImage.getRaster().setSample(x, y, 0, 1); // 白色 } } } // TODO: 更高级的预处理包括: // - 去除干扰线、噪点 // - 字符分割(如果字符粘连) // - 倾斜校正 // - 调整亮度和对比度等 // 你可能需要引入更专业的图像处理库或算法 // 为了调试,可以将预处理后的图片保存下来查看效果 try { File outputfile = new File("preprocessed_captcha.png"); ImageIO.write(binaryImage, "png", outputfile); System.out.println("Preprocessed image saved to " + outputfile.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } return binaryImage; // 返回预处理后的图片 } /** * 使用 Tess4J 识别图片中的文字 * @param image 待识别的图片 (最好是预处理后的) * @return 识别出的字符串 */ public static String recognizeCaptcha(BufferedImage image) { Tesseract tesseract = new Tesseract(); // 设置 tessdata 路径 (如果 TESSDATA_PATH 已正确设置且 Tesseract 安装正确,这行可能不是必需的,Tess4J 会自动查找) // 但显式设置更保险 if (TESSDATA_PATH != null && !TESSDATA_PATH.isEmpty()) { tesseract.setDatapath(TESSDATA_PATH); } else { System.out.println("TESSDATA_PATH not set. Tess4J will try to find tessdata automatically."); } tesseract.setLanguage("eng"); // 设置识别语言为英文 (通常包含数字) // 如果验证码只有数字,可以尝试设置仅识别数字 // tesseract.setTessVariable("tessedit_char_whitelist", "0123456789"); try { String result = tesseract.doOCR(image); // 清理识别结果,去除空格或换行符等 result = result.trim().replaceAll("[^0-9a-zA-Z]", ""); // 根据验证码内容调整清理规则 System.out.println("OCR Result: " + result); return result; } catch (TesseractException e) { System.err.println("Error during OCR: " + e.getMessage()); return null; // 识别失败 } } // 示例如何在你的爬虫流程中使用 public static void main(String[] args) { String captchaImageUrl = "YOUR_CAPTCHA_IMAGE_URL"; // 从页面解析获取到的验证码图片 URL try { // 1. 下载图片 BufferedImage originalCaptchaImage = downloadImage(captchaImageUrl); System.out.println("Image downloaded."); // 2. 预处理图片 BufferedImage preprocessedImage = preprocessImage(originalCaptchaImage); System.out.println("Image preprocessed."); // 3. 识别验证码 String captchaCode = recognizeCaptcha(preprocessedImage); if (captchaCode != null && !captchaCode.isEmpty()) { System.out.println("Recognized CAPTCHA: " + captchaCode); // 4. 将 captchaCode 填入 POST 数据中,提交表单 // ... (你的 ASP.NET WebForms POST 提交代码,将 captchaCode 放到对应的隐藏字段或输入框字段中) ... // 例如:postData += "&captchaInputFieldName=" + URLEncoder.encode(captchaCode, StandardCharsets.UTF_8.name()); // ... 提交 POST 请求 ... } else { System.out.println("Failed to recognize CAPTCHA."); // 5. 处理识别失败的情况,可能需要重试或记录日志 } } catch (IOException e) { System.err.println("Error downloading or processing image: " + e.getMessage()); } // catch (URISyntaxException e) { // System.err.println("Invalid URL: " + e.getMessage()); // } // 如果你的 downloadImage 方法 throws URISyntaxException } }