如何使用SeleniumWebDriver和Java从图像(captcha)读取文本

如何使用SeleniumWebDriver和Java从图像(captcha)读取文本,java,selenium,selenium-webdriver,captcha,Java,Selenium,Selenium Webdriver,Captcha,我有注册网页,但在最后的验证码显示 我无法从图像中读取文本。我将提到代码和输出 @Test public void loginTest() throws InterruptedException { System.out.println("Testing"); driver.get("https://customer.onlinelic.in/ForgotPwd.htm"); WebElement element = driver.findElement(By.xpat

我有注册网页,但在最后的验证码显示

我无法从图像中读取文本。我将提到代码和输出

@Test
public void loginTest() throws InterruptedException {
    System.out.println("Testing");
    driver.get("https://customer.onlinelic.in/ForgotPwd.htm");

    WebElement element = driver.findElement(By.xpath("//*[@id='forgotPassword']/table/tbody/tr[5]/td[3]/img"));
    System.out.println(" get the instance ");

    String elementTest = element.getAttribute("src");
    System.out.println("Element : " + elementTest);
}
输出:错误

线程“main”org.openqa.selenium.NoSuchElementException中的异常: 找不到元素: {“方法”:“xpath”,“选择器”:“/[@id='forgotPassword']/table/tbody/tr[5]/td[3]/img”} 命令持续时间或超时:60.02秒有关此错误的文档,请访问: 构建信息: 版本:“2.35.0”,修订版:“8df0c6b”,时间:“2013-08-12 15:43:19” 系统信息:os.name:'Windows 7',os.arch:'amd64',os.version: “6.1”,java.version:“1.6.0_26”会话ID: 5f5b2e1a-56a4-49ad-8fd3-2870747a7768驾驶员信息: org.openqa.selenium.firefox.FirefoxDriver功能[{platform=XP, acceptSslCerts=true,javascriptEnabled=true,browserName=firefox, rotatable=false,locationContextEnabled=true,version=23.0.1, CSSSelectorEnabled=true,databaseEnabled=true,handlesAlerts=true, browserConnectionEnabled=true,nativeEvents=true, WebStorage Enabled=true,applicationCacheEnabled=true, takesScreenshot=true}]at sun.reflect.NativeConstructorAccessorImpl.newInstance0(本机方法) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 位于java.lang.reflect.Constructor.newInstance(Constructor.java:513) 在 org.openqa.selenium.remote.ErrorHandler.CreateTrowable(ErrorHandler.java:191) 在 org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:145) 在 org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:554) 在 org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:307) 在 org.openqa.selenium.remote.RemoteWebDriver.findelementbypath(RemoteWebDriver.java:404) 位于org.openqa.selenium.By$ByXPath.findelelement(By.java:344) org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:299) 在seleniumtest.CaptchaTest.loginTest(CaptchaTest.java:41)上 seleniumtest.CaptchaTest.main(CaptchaTest.java:59)由以下原因引起: org.openqa.selenium.remote.ErrorHandler$UnknownServerException:无法 要定位元素,请执行以下操作: {“方法”:“xpath”,“选择器”:“/[@id='forgotPassword']/table/tbody/tr[5]/td[3]/img”} 构建信息:版本:'2.35.0',修订版:'8df0c6b',时间:'2013-08-12 15:43:19'系统信息:os.name:'Windows 7',os.arch:'amd64', os.version:'6.1',java.version:'1.6.0_26'驱动程序信息: driver.version:未知,位于.FirefoxDriver.prototype.findElementInternal_(file:///C:/Users/lukup/AppData/Local/Temp/anonymous4043037924964932185webdriver-简介/扩展/fxdriver@googlecode.com/components/driver_component.js:8880) at.fxdriver.Timer.prototype.setTimeout/有两个问题

  • 您使用了错误的xpath,因此得到了NoTouchElement异常

  • 即使您使用了正确的xpath,也无法提取文本,因为如果使用CAPTCHA,这将违背这一点


  • 无法读取验证码。如果您可以读取验证码,那么使用验证码是没有意义的。

    忘记密码表单位于iframe中。这就是硒找不到元素的原因。您需要首先切换到保存表单的iframe,然后运行findelement。您的xpath是正确的

    使用
    driver.switchTo().frame(arg0)
    切换到帧中。参见javadoc


    为了得到验证码文本,我不明白你所说的“存储测试和比较”是什么意思。理想情况下,您不应该能够从验证码中读取文本(正如其他人所提到的)。我见过的另一种方法是,在开发和QA环境中将captcha值存储为
    alt text
    。这样您就可以阅读它并在文本框中输入。当代码进入生产环境或任何外部环境时,可以删除此
    alt text

    验证码的全部目的是防止UI自动化!您可能需要使用内部API来验证操作。

    为了详细说明前面的答案,CAPTCHA是“完全自动化的公共图灵测试”的缩写,用于区分计算机和人类。 所以,如果“机器”能解决这个问题,它就不是真正的本职工作

    为了解决这个问题,您可以做一些事情——使用外部服务的API,例如。 实现他们的API,向他们传递验证码并返回文本。我观察到的平均求解时间约为10-15秒

    实施示例(摘自)


    我有一个解决方案,将为一个特定的网站工作。您可以获取整个页面的快照并获取验证码图像。然后将captcha图像的整个宽度除以字符总数(在captcha中通常是常量)。现在我们有了验证码图像的各个字符。通过重新加载页面收集验证码的所有可能字符

    一旦你有了所有可能的字符,然后给任何验证码图像,你可以比较它的字符与我们的图像,并决定它是哪个字母或数字

    应采取的步骤:

  • 收集验证码图像并将其划分为单个字符

    private static BufferedImage cropImage(File filePath, int x, int y, int w,
                int h) {
    
            try {
                BufferedImage originalImgage = ImageIO.read(filePath);
                BufferedImage subImgage = originalImgage.getSubimage(x, y, w, h);
    
                return subImgage;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }
    
  • 将所有可能的图像保存在一个文件夹中

  • 现在读取验证码的每个字符图像,并将其与上面文件夹中的所有其他图像进行比较。 可以使用像素值比较两个图像 公共静态浮点getDiff(文件f1、文件f2、整型宽度、整型高度) 抛出IOException{ BuffereImage bi1=null; BuffereImage bi2=null; bi1=新的BuffereImage(宽度、高度、BuffereImage.TYPE_INT_ARGB); bi2=新的BuffereImage(宽度、高度、BuffereImage.TYPE_INT_ARGB)

    
    
    private static BufferedImage cropImage(File filePath, int x, int y, int w,
                int h) {
    
            try {
                BufferedImage originalImgage = ImageIO.read(filePath);
                BufferedImage subImgage = originalImgage.getSubimage(x, y, w, h);
    
                return subImgage;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }
    
            bi1 = ImageIO.read(f1);
            bi2 = ImageIO.read(f2);
            float diff = 0;
            for (int i = 0; i < width; i++) {
                for (int j = 0; j < height; j++) {
                    int rgb1 = bi1.getRGB(i, j);
                    int rgb2 = bi2.getRGB(i, j);
    
                    int b1 = rgb1 & 0xff;
                    int g1 = (rgb1 & 0xff00) >> 8;
                    int r1 = (rgb1 & 0xff0000) >> 16;
    
                    int b2 = rgb2 & 0xff;
                    int g2 = (rgb2 & 0xff00) >> 8;
                    int r2 = (rgb2 & 0xff0000) >> 16;
    
                    diff += Math.abs(b1 - b2);
                    diff += Math.abs(g1 - g2);
                    diff += Math.abs(r1 - r2);
                }
            }
            return diff;
        }
    
    import java.awt.Image;
    import java.awt.image.BufferedImage;
    import java.awt.image.RenderedImage;
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    import javax.imageio.ImageIO;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.firefox.FirefoxDriver;
    import org.testng.annotations.BeforeTest;
    import org.testng.annotations.Test;
    import com.asprise.util.ocr.OCR;
    
    public class ExtractImage {
    
     WebDriver driver;
    
     @BeforeTest
      public void setUpDriver() {
       driver = new FirefoxDriver();
      }
    
     @Test
     public void start() throws IOException{
    
     /*Navigate to http://www.mythoughts.co.in/2013/10/extract-and-verify-text-from-image.html page
      * and get the image source attribute
      *  
      */  
     driver.get("http://www.mythoughts.co.in/2013/10/extract-and-verify-text-from-image.html");
     String imageUrl=driver.findElement(By.xpath("//*[@id='post-body-5614451749129773593']/div[1]/div[1]/div/a/img")).getAttribute("src");
     System.out.println("Image source path : \n"+ imageUrl);
    
     URL url = new URL(imageUrl);
     Image image = ImageIO.read(url);
     String s = new OCR().recognizeCharacters((RenderedImage) image);
     System.out.println("Text From Image : \n"+ s);
     System.out.println("Length of total text : \n"+ s.length());
     driver.quit();
    
     /* Use below code If you want to read image location from your hard disk   
      *   
       BufferedImage image = ImageIO.read(new File("Image location"));   
       String imageText = new OCR().recognizeCharacters((RenderedImage) image);  
       System.out.println("Text From Image : \n"+ imageText);  
       System.out.println("Length of total text : \n"+ imageText.length());   
    
       */ 
    }
    
    }