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

    奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  2. 5月9日——vue渲染过程中{{xxx}}显示

    异常显示的原因: 这是由于浏览器的渲染机制导致的,浏览器是从头到尾  如果你的js引用在底部,那么浏览器会先加载dom此时,你用于渲染的{{}}识别符,因为还没读到该识别符对应的js文件,所以会被解析 ...

  3. .Net 多线程 异步编程 Await、Async和Task

    await和async简介   await和async是在C#5中引入,并且在.NetFramewor4.5以及.NetCore中进行了支持.主要是解决性能瓶颈,并且增强系统的响应能力. msdn关于 ...

  4. 【代码笔记】iOS-键盘自适应弹出

    一,效果图. 二,工程图. 三,代码. ViewController.h #import <UIKit/UIKit.h> @interface ViewController : UIVie ...

  5. JS中判断数据类型的几种方法

    1⃣️首先我们来了解一下js中的数据类型 1.基本数据类型:Undefined.Null.Boolean.Number.String(值类型) 2.复杂数据类型:Object(引用类型) (值类型和引 ...

  6. kotlin3-IdeaIU编辑器字体自动放大缩小

  7. 用php和ajax写一个省市区的三级联动,实现地区的下拉选择

    要实现这个页面的三级联动,我们需要建立三个php文件,第一个php文件我们导入jQuery文件,里面嵌入JavaScript:第二个php文件我们做一个php的处理页面,里面引入我们封装好的数据库类文 ...

  8. window下安装RabbitMQ

    RabbitMQ: MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们.消 ...

  9. Python笔记(六):推导数据

    (一)  准备工作 创建1个文件记录运动员的跑步成绩 james.txt 2-34,3:21,2.34,2.45,3.01,2:01,2:01,3:10,2-22 (二)  要求 在屏幕上输出运动员最 ...

  10. 解决mysql日志显示时间和“Got an error reading communication packets” 问题

    [root@calldb3 data]# tail -f mysql.error :.884160Z to db: 'calldb' user: 'call' host: '172.31.50.220 ...