在做自动化测试或压力测试时,验证码总是一个问题。在以往的压力测试经历中,测试一般在独立的测试环境中进行,可以放心禁用验证码或使用万能验证码,这个是最实用的。但是,这两天我尝试了一个使用第三方的图形图像识别工具来完成验证码识别并通过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

Jmeter—实现识别验证码登录的更多相关文章

  1. selenium自动化 | 借助百度AI开放平台识别验证码登录职教云

    #通过借助百度AI开放平台识别验证码登录职教云 from PIL import Image from aip import AipOcr import unittest # driver.get(zj ...

  2. 百度api识别验证码登录

    import time from selenium import webdriver from aip import AipOcr def initial(): """ ...

  3. jmeter跳过验证码登录配置:通过手动添加 Cookie 跳过带验证码的登录接口

    目录 一.基本配置 二.HTTP请求默认值 三.HTTP信息头管理器 四.HTTP Cookie管理器 五.线程组下接口设置 一.基本配置 二.HTTP请求默认值 (1)jmeter的设置: (2)设 ...

  4. 微博验证码的识别并登录获取cookies

    记得以前微博是用的宫格验证码,现在不一样了,用的是滑块验证码和 点触验证码,每天登陆的第一次基本用的是滑块,继续登录就都用的是点触验证码.所以滑块验证码不写,感兴趣的可以补上. 代码: 这里用的超级鹰 ...

  5. 【转载】loadrunner使用system()函数调用Tesseract-OCR识别验证码遇到的问题

    俗话说前人栽树,后人乘凉,此话一点不假,结合云层的一遍文章:http://bbs.51testing.com/thread-533920-1-1.html,知道还有一个Tesseract-OCR可以用 ...

  6. loadrunner使用system()函数调用Tesseract-OCR识别验证码遇到的问题

    俗话说前人栽树,后人乘凉,此话一点不假,结合云层的一遍文章:http://bbs.51testing.com/thread-533920-1-1.html,知道还有一个Tesseract-OCR可以用 ...

  7. 使用python识别验证码

    公司的登录注册等操作有验证码,测试环境可以让开发屏蔽掉验证码,但是如果到线上的话就要想办法识别验证码或必过验证码了. 识别验证码主要分为三部分,一.对验证码进行二值化.二.将二值化后的图片分割.三.进 ...

  8. python网络爬虫之如何识别验证码

    有些网站的登录方式是验证码登录的方式,比如今天我们要测试的网站专利检索及分析. http://www.pss-system.gov.cn/sipopublicsearch/portal/uilogin ...

  9. Python 实现简单图片验证码登录

    朋友说公司要在测试环境做接口测试,登录时需要传入正确的图片的验证码,本着懒省事的原则,推荐他把测试环境的图片验证码写死,我们公司也是这么做的^_^.劝说无果/(ㄒoㄒ)/~~,只能通过 OCR 技术来 ...

随机推荐

  1. 自定义MVC框架之工具类-模型类

    截止目前已经改造了5个类: ubuntu:通过封装验证码类库一步步安装php的gd扩展 自定义MVC框架之工具类-分页类的封装 自定义MVC框架之工具类-文件上传类 自定义MVC框架之工具类-图像处理 ...

  2. forever 启动nodejs

    forever可以看做是一个nodejs的守护进程,能够启动,停止,重启我们的app应用. 1.全局安装 forever // 记得加-g,forever要求安装到全局环境下 sudo npm ins ...

  3. Vue.js之路由系统

    Vue.js生态之vue-router vue-router是什么? vue-router是Vue的路由系统,定位资源的,我们可以不进行整页刷新去切换页面内容. vue-router的安装与基本配置 ...

  4. 关于flex布局兼容

    (做个记录) 一.W3C各个版本的flex 2009 version 标志:display: box; or a property that is box-{*} (eg. box-pack) 201 ...

  5. art-template模板应用

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  6. 让你的app体验更丝滑的11种方法!冲击手机应用榜单Top3指日可待

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由WeTest质量开放平台团队发表于云+社区专栏 一款app除了要有令人惊叹的功能和令人发指交互之外,在性能上也应该追求丝滑的要求,这样 ...

  7. MySQL——索引实现原理

    在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式. MyISAM索引实现 MyISAM引擎使用B+Tr ...

  8. AngularJS简单入门

    什么是AngularJS AngularJS是一款优秀的前端JS框架,是Google多款产品之一,简称ng. ng有着诸多特性,最为核心的是:MVVM.模块化.自动化双向数据绑定.语义化标签.依赖注入 ...

  9. python生成式和生成器

    一,生成式和生成器 1,列表生成式 mylist = [ i*i for i in range(3) if i>1 ] print(mylist) 运行结果:[4] 可以发现,快速生成列表的表达 ...

  10. Java 如何启用 ARM 虚拟机诊断

    现象描述 如何通过 Java 语言实现在创建 ARM 虚拟机时开启诊断,并配置相关指标.   实现思路 调研最高版本的 JAVA SDK(1.1.0)源码发现,SDK 层面并未提供任启动诊断和配置诊断 ...