You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
7.5 KiB

7 months ago
  1. package com.example;
  2. import java.awt.image.BufferedImage;
  3. import java.io.*;
  4. import java.net.HttpURLConnection;
  5. import java.net.URL;
  6. import javax.imageio.ImageIO;
  7. import net.sourceforge.tess4j.Tesseract;
  8. import net.sourceforge.tess4j.TesseractException;
  9. // ... 其他必要的导入 ...
  10. public class CaptchaOCR {
  11. // Tesseract data 路径 (tessdata 文件夹所在目录)
  12. // Windows 示例: "C:\\Program Files\\Tesseract-OCR\\tessdata"
  13. // Linux/macOS 示例: 通常不需要设置,Tess4J 会自动查找
  14. private static final String TESSDATA_PATH = "F:\\tool\\Tesseract-OCR\\tessdata"; // 根据你的安装路径修改
  15. /**
  16. * 下载验证码图片
  17. * @param imageUrl 图片的完整 URL
  18. * @return 图片的 BufferedImage 对象
  19. * @throws IOException 如果下载失败
  20. */
  21. public static BufferedImage downloadImage(String imageUrl) throws IOException {
  22. URL url = new URL(imageUrl);
  23. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  24. conn.setRequestMethod("GET");
  25. // 添加 User-Agent 等必要的请求头,模拟浏览器
  26. 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");
  27. // ... 其他头 ...
  28. int responseCode = conn.getResponseCode();
  29. if (responseCode == HttpURLConnection.HTTP_OK) {
  30. try (InputStream is = conn.getInputStream()) {
  31. // 将输入流读取到字节数组,ImageIO 从字节数组读取更稳定
  32. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  33. byte[] buffer = new byte[4096]; // 缓冲区大小,可以调整
  34. int bytesRead;
  35. while ((bytesRead = is.read(buffer)) != -1) {
  36. baos.write(buffer, 0, bytesRead);
  37. }
  38. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  39. BufferedImage image = ImageIO.read(bais);
  40. if (image == null) {
  41. throw new IOException("Failed to read image from stream. Check image format.");
  42. }
  43. return image;
  44. }
  45. } else {
  46. throw new IOException("Failed to download image. HTTP error code: " + responseCode);
  47. }
  48. }
  49. /**
  50. * 对验证码图片进行预处理 (基础示例转灰度+二值化)
  51. * 这是最关键的部分需要根据验证码样式调整
  52. * @param originalImage 原始图片
  53. * @return 预处理后的图片
  54. */
  55. public static BufferedImage preprocessImage(BufferedImage originalImage) {
  56. // TODO: 这里是图像预处理的重点,需要根据实际验证码样式进行调整和优化
  57. // 基础处理:转灰度 -> 二值化
  58. int width = originalImage.getWidth();
  59. int height = originalImage.getHeight();
  60. BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
  61. grayImage.getGraphics().drawImage(originalImage, 0, 0, null);
  62. BufferedImage binaryImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
  63. // 二值化阈值,可能需要调整 (0-255)
  64. int threshold = 128;
  65. for (int y = 0; y < height; y++) {
  66. for (int x = 0; x < width; x++) {
  67. int gray = grayImage.getRaster().getSample(x, y, 0);
  68. if (gray < threshold) {
  69. binaryImage.getRaster().setSample(x, y, 0, 0); // 黑色
  70. } else {
  71. binaryImage.getRaster().setSample(x, y, 0, 1); // 白色
  72. }
  73. }
  74. }
  75. // TODO: 更高级的预处理包括:
  76. // - 去除干扰线、噪点
  77. // - 字符分割(如果字符粘连)
  78. // - 倾斜校正
  79. // - 调整亮度和对比度等
  80. // 你可能需要引入更专业的图像处理库或算法
  81. // 为了调试,可以将预处理后的图片保存下来查看效果
  82. try {
  83. File outputfile = new File("preprocessed_captcha.png");
  84. ImageIO.write(binaryImage, "png", outputfile);
  85. System.out.println("Preprocessed image saved to " + outputfile.getAbsolutePath());
  86. } catch (IOException e) {
  87. e.printStackTrace();
  88. }
  89. return binaryImage; // 返回预处理后的图片
  90. }
  91. /**
  92. * 使用 Tess4J 识别图片中的文字
  93. * @param image 待识别的图片 (最好是预处理后的)
  94. * @return 识别出的字符串
  95. */
  96. public static String recognizeCaptcha(BufferedImage image) {
  97. Tesseract tesseract = new Tesseract();
  98. // 设置 tessdata 路径 (如果 TESSDATA_PATH 已正确设置且 Tesseract 安装正确,这行可能不是必需的,Tess4J 会自动查找)
  99. // 但显式设置更保险
  100. if (TESSDATA_PATH != null && !TESSDATA_PATH.isEmpty()) {
  101. tesseract.setDatapath(TESSDATA_PATH);
  102. } else {
  103. System.out.println("TESSDATA_PATH not set. Tess4J will try to find tessdata automatically.");
  104. }
  105. tesseract.setLanguage("eng"); // 设置识别语言为英文 (通常包含数字)
  106. // 如果验证码只有数字,可以尝试设置仅识别数字
  107. // tesseract.setTessVariable("tessedit_char_whitelist", "0123456789");
  108. try {
  109. String result = tesseract.doOCR(image);
  110. // 清理识别结果,去除空格或换行符等
  111. result = result.trim().replaceAll("[^0-9a-zA-Z]", ""); // 根据验证码内容调整清理规则
  112. System.out.println("OCR Result: " + result);
  113. return result;
  114. } catch (TesseractException e) {
  115. System.err.println("Error during OCR: " + e.getMessage());
  116. return null; // 识别失败
  117. }
  118. }
  119. // 示例如何在你的爬虫流程中使用
  120. public static void main(String[] args) {
  121. String captchaImageUrl = "YOUR_CAPTCHA_IMAGE_URL"; // 从页面解析获取到的验证码图片 URL
  122. try {
  123. // 1. 下载图片
  124. BufferedImage originalCaptchaImage = downloadImage(captchaImageUrl);
  125. System.out.println("Image downloaded.");
  126. // 2. 预处理图片
  127. BufferedImage preprocessedImage = preprocessImage(originalCaptchaImage);
  128. System.out.println("Image preprocessed.");
  129. // 3. 识别验证码
  130. String captchaCode = recognizeCaptcha(preprocessedImage);
  131. if (captchaCode != null && !captchaCode.isEmpty()) {
  132. System.out.println("Recognized CAPTCHA: " + captchaCode);
  133. // 4. 将 captchaCode 填入 POST 数据中,提交表单
  134. // ... (你的 ASP.NET WebForms POST 提交代码,将 captchaCode 放到对应的隐藏字段或输入框字段中) ...
  135. // 例如:postData += "&captchaInputFieldName=" + URLEncoder.encode(captchaCode, StandardCharsets.UTF_8.name());
  136. // ... 提交 POST 请求 ...
  137. } else {
  138. System.out.println("Failed to recognize CAPTCHA.");
  139. // 5. 处理识别失败的情况,可能需要重试或记录日志
  140. }
  141. } catch (IOException e) {
  142. System.err.println("Error downloading or processing image: " + e.getMessage());
  143. }
  144. // catch (URISyntaxException e) {
  145. // System.err.println("Invalid URL: " + e.getMessage());
  146. // } // 如果你的 downloadImage 方法 throws URISyntaxException
  147. }
  148. }