zoukankan      html  css  js  c++  java
  • Jmeter—实现识别验证码登录

    在做自动化测试或压力测试时,验证码总是一个问题。在以往的压力测试经历中,测试一般在独立的测试环境中进行,可以放心禁用验证码或使用万能验证码,这个是最实用的。但是,这两天我尝试了一个使用第三方的图形图像识别工具来完成验证码识别并通过Jmeter完成登录的过程,识别工具的识别成功率有限,因此本篇估计仅能在理论范围内适用。

    本篇内容大部分内容来自于该作者的文章:http://blog.csdn.net/xreztento/article/details/48682923

    总体目的:给Jmeter写一个后置处理器,用来将上一个请求响应返回的验证码图片识别成文字,并将识别内容保存为Jmeter的一个参数,这个参数供登录post请求进行登录验证,从而完成登录的自动化过程。

    工具

     (1)第三方图形图像识别工具:tesseract-ocr  下载地址:http://code.google.com/p/tesseract-ocr/downloads/list  基本无法下载,已上传到我的百度网盘

     安装后,可以在cmd下试一试是否安装成功:

     在cmd下输入命令:tesseract d:123.jpg result -l eng   意思是将D盘下的123.jpg 识别后放在result.txt下

     (2)需要用到的jar包:

     Jmeter插件开发相关的jar包: ApacheJmeter_core.jar jorphon.jar logkit-2.0.jar  这些在Jmeter的lib中都有 直接导入工程项目即可

     图形处理相关的jar包:jai-imageio-1.1.jar  swingx-1.6.1.jar  从网上下的,已上传到百度云盘 jar 文件夹下

    插件开发

    用java IDE新建一个工程项目,实现两个部分,一个是识别图片,一个是Jmeter插件的UI部分。工程项目完成目录为:

    package com.test.huu;
    import java.awt.Color;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.Locale;
    
    import javax.imageio.IIOImage;
    import javax.imageio.ImageIO;
    import javax.imageio.ImageReader;
    import javax.imageio.ImageWriteParam;
    import javax.imageio.ImageWriter;
    import javax.imageio.metadata.IIOMetadata;
    import javax.imageio.stream.ImageInputStream;
    import javax.imageio.stream.ImageOutputStream;
    
    import com.sun.media.imageio.plugins.tiff.TIFFImageWriteParam;
    
    public class ImageIOHelper{
        public static File createImage(File imageFile, String imageFormat) {
    
            File tempFile = null;
            ImageInputStream iis = null;
            ImageOutputStream ios = null;
            ImageReader reader = null;
            ImageWriter writer = null;
    
            try {
                Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(imageFormat);
                reader = readers.next();
    
                iis = ImageIO.createImageInputStream(imageFile);
                reader.setInput(iis);
    
                IIOMetadata streamMetadata = reader.getStreamMetadata();
                            TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam(Locale.CHINESE);
                tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);
                Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("tiff");
                writer = writers.next();
    
                BufferedImage bi = removeBackgroud(reader.read(0));
                IIOImage image = new IIOImage(bi,null,reader.getImageMetadata(0));
                tempFile = tempImageFile(imageFile);
    
                ios = ImageIO.createImageOutputStream(tempFile);
                writer.setOutput(ios);
                writer.write(streamMetadata, image, tiffWriteParam);
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                if(iis != null){
                    try {
                        iis.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(ios != null){
                    try {
                        ios.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(writer != null){
                    writer.dispose();
                }
                if(reader != null){
                    reader.dispose();
                }
    
            }
            return tempFile;
        }
    
        private static File tempImageFile(File imageFile) {
            String path = imageFile.getPath();
            StringBuffer strB = new StringBuffer(path);
            return new File(strB.toString().replaceFirst("jpg", "tif"));
        }
        
        //给图片降噪 提高识别度
        public static int isFilter(int colorInt) {  
            Color color = new Color(colorInt);
            if ((color.getRed() > 85 && color.getRed() < 255) 
                    && (color.getGreen() > 85 && color.getGreen() < 255) 
                    && (color.getBlue() > 85 && color.getBlue() < 255)) {  
                return 1;  
            }  
            return 0;
        }
        
        public static BufferedImage removeBackgroud(BufferedImage img)  
                throws Exception {  
            int width = img.getWidth();  
            int height = img.getHeight();  
            for (int x = 0; x < width; ++x) {  
                for (int y = 0; y < height; ++y) {  
                    if (isFilter(img.getRGB(x, y)) == 1) {  
                       img.setRGB(x, y, Color.WHITE.getRGB());  
                    }
                }  
            }  
            return img;
        } 
        
    }
    ImageIOHelper.java
    package com.test.huu;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    
    public class OCR {
        private final String LANG_OPTION = "-l";
        private final String EOL = System.getProperty("line.separator");
        private String tessPath = "D://Program Files (x86)//Tesseract-OCR";
    
        public String recognizeText(File imageFile,String imageFormat) {
            File tempImage = ImageIOHelper.createImage(imageFile,imageFormat);
            File outputFile = new File(imageFile.getParentFile(),"output" + imageFile.getName());
            StringBuffer sb = new StringBuffer();
            List<String> cmd = new ArrayList<String>();
    
            cmd.add(tessPath+"//tesseract");
            cmd.add("");
            cmd.add(outputFile.getName());
            cmd.add(LANG_OPTION);
            cmd.add("eng");     
            ProcessBuilder pb = new ProcessBuilder();
            pb.directory(imageFile.getParentFile());
    
            cmd.set(1, tempImage.getName());
            pb.command(cmd);
            pb.redirectErrorStream(true);
    
            Process process = null;
            BufferedReader in = null;
            int wait;
            try {
                process = pb.start();
                //tesseract.exe xxx.tif 1 -l eng
                wait = process.waitFor();
                if(wait == 0){
                    in = new BufferedReader(new InputStreamReader(new FileInputStream(outputFile.getAbsolutePath()+".txt"),"UTF-8"));
                    String str;
                    while((str = in.readLine())!=null){
                        sb.append(str).append(EOL);
                    }
                    in.close();
    
                }else{
    
                    tempImage.delete();
                }
                new File(outputFile.getAbsolutePath()+".txt").delete();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                if(in != null){
                    try {
                        in.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
    
            tempImage.delete();
            return sb.toString();
        }
    }
    OCR.java
    package com.test.huu;
    
    import java.io.File;  
      
    public class TestOCR {  
      
     public static void main(String[] args) {  
            String path = "D://124.jpg";       
            System.out.println("ORC Test Begin......");  
            try {       
                String valCode = new OCR().recognizeText(new File(path), "jpeg");       
                System.out.println(valCode);       
            } catch (Exception e) {    
                e.printStackTrace();    
            }         
            System.out.println("ORC Test End......");  
        }    
      
    }  
    TestOCR.java
    package com.test.huu;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.Serializable;
    
    import org.apache.jmeter.processor.PostProcessor;
    import org.apache.jmeter.samplers.SampleResult;
    import org.apache.jmeter.testelement.AbstractScopedTestElement;
    import org.apache.jmeter.threads.JMeterContext;
    import org.apache.jmeter.threads.JMeterVariables;
    import org.apache.jorphan.logging.LoggingManager;
    import org.apache.log.Logger;
    
    public class VcodeExtractor extends AbstractScopedTestElement implements PostProcessor, Serializable{
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        /**
         * 
         */
        private static final Logger log = LoggingManager.getLoggerForClass();
        
        @Override
        public void process() {
    
            // TODO Auto-generated method stub
            JMeterContext context = getThreadContext();
            SampleResult previousResult = context.getPreviousResult();
            if (previousResult == null) {
                return;
            }
            log.debug("VcodeExtractor processing result");
    
            String status = previousResult.getResponseCode();
            int id = context.getThreadNum();
    //        String imageName = id + ".jpg";
            String path = "D://" + id + ".jpg";
    
            if(status.equals("200")){
                byte[] buffer = previousResult.getResponseData();
                FileOutputStream out = null;
                File file = null;
                try {
                    file = new File(path);
                    out = new FileOutputStream(file);
                    out.write(buffer);
                    out.flush();
    
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    if(out != null){
                        try {
                            out.close();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
    
                  try {   
                    String vcode = new OCR().recognizeText(file, "jpeg"); 
                    vcode = vcode.replace(" ", "").trim();
                    
                    JMeterVariables var = context.getVariables();
                    var.put("vcode", vcode);
    //                var.put("vuser", String.valueOf(id));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }    
            }
    
        }
    
    }
    VodeExtractor.java
    package com.test.huu;
    import org.apache.jmeter.processor.gui.AbstractPostProcessorGui;
    import org.apache.jmeter.testelement.TestElement;
    
    public class VcodeExtractorGUI extends AbstractPostProcessorGui{
    
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
    
        /**
         * 
         */
        @Override
        public TestElement createTestElement() {
            // TODO Auto-generated method stub
            VcodeExtractor extractor = new VcodeExtractor();
            modifyTestElement(extractor);
            return extractor;
        }
    
        @Override
        public String getLabelResource() {
            // TODO Auto-generated method stub
            return this.getClass().getName();
        }
    
        @Override
        public String getStaticLabel() {//设置显示名称
            // TODO Auto-generated method stub
            return "VcodeExtractor";
        }
    
        @Override
        public void modifyTestElement(TestElement extractor) {
            // TODO Auto-generated method stub
            super.configureTestElement(extractor);
    
        }
    }
    VcodeExtractorGUI.java

    插件生成

    插件开发完成后,在Eclipse中 export-Runnable jar file ,将必要的依赖库加进去,最后会生成一个 .jar 文件

    注意:图形相关的jar包  直接使用时会报错(Jmeter会报一个错:java.lang.IllegalArgumentException: vendorName == null) 最终在网上找到了解决方案

    生成jar包后,用解压工具打开,将 /META-INF 目录下的 MANIFEST.MF 文件用编辑器(我用的是sublime)打开,拷贝进去下面一段代码,保存压缩包:

    Specification-Title: Java Advanced Imaging Image I/O Tools
    Specification-Version: 1.1
    Specification-Vendor: Sun Microsystems, Inc.
    Implementation-Title: com.sun.media.imageio
    Implementation-Version: 1.1
    Implementation-Vendor: Sun Microsystems, Inc.

    插件插入Jmeter

    将 .jar 文件放入Jmeter 安装路径下 lib/ext/ 目录下,重启Jmeter

    可以看到,我们新开发的后置处理器 VcodeExtractor 

    再看下大致的登录过程测试计划:

    登录的post请求参数中,可以使用Vcode,Vcode是我们开发的后置处理器 VcodeExtrator 返回的从图片验证码中识别出来的字符串

    插件效果验证

    把测试计划跑一次  根据察看结果树  看下效果

     

    登录请求成功啦,但是图片识别也不是百分百成功,部分失败情况下,登录请求肯定会失败。Tesseract-OCR也有训练识别的功能,但是不再继续研究了。

    关于Tesseract-OCR的延展性学习可参考:

    (1)http://www.cnblogs.com/alex-blog/archive/2012/10/08/2714984.html

    (2)http://blog.csdn.net/ycb1689/article/details/8520954

    (3)http://www.52itstyle.com/thread-4803-1-1.html

  • 相关阅读:
    day16作业 后台管理
    华为园区网实验
    静态路由与思科的区别
    JUnit 两日游
    SQL语句学习积累·数据的操作
    僵固式思维 OR 成长式思维
    压测噩梦后的小感想
    跌跌撞撞的三年
    Linux命令累积
    LoadRunner 学习(基础一)
  • 原文地址:https://www.cnblogs.com/hnini/p/6007742.html
Copyright © 2011-2022 走看看