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
Jmeter—实现识别验证码登录的更多相关文章
- selenium自动化 | 借助百度AI开放平台识别验证码登录职教云
#通过借助百度AI开放平台识别验证码登录职教云 from PIL import Image from aip import AipOcr import unittest # driver.get(zj ...
- 百度api识别验证码登录
import time from selenium import webdriver from aip import AipOcr def initial(): """ ...
- jmeter跳过验证码登录配置:通过手动添加 Cookie 跳过带验证码的登录接口
目录 一.基本配置 二.HTTP请求默认值 三.HTTP信息头管理器 四.HTTP Cookie管理器 五.线程组下接口设置 一.基本配置 二.HTTP请求默认值 (1)jmeter的设置: (2)设 ...
- 微博验证码的识别并登录获取cookies
记得以前微博是用的宫格验证码,现在不一样了,用的是滑块验证码和 点触验证码,每天登陆的第一次基本用的是滑块,继续登录就都用的是点触验证码.所以滑块验证码不写,感兴趣的可以补上. 代码: 这里用的超级鹰 ...
- 【转载】loadrunner使用system()函数调用Tesseract-OCR识别验证码遇到的问题
俗话说前人栽树,后人乘凉,此话一点不假,结合云层的一遍文章:http://bbs.51testing.com/thread-533920-1-1.html,知道还有一个Tesseract-OCR可以用 ...
- loadrunner使用system()函数调用Tesseract-OCR识别验证码遇到的问题
俗话说前人栽树,后人乘凉,此话一点不假,结合云层的一遍文章:http://bbs.51testing.com/thread-533920-1-1.html,知道还有一个Tesseract-OCR可以用 ...
- 使用python识别验证码
公司的登录注册等操作有验证码,测试环境可以让开发屏蔽掉验证码,但是如果到线上的话就要想办法识别验证码或必过验证码了. 识别验证码主要分为三部分,一.对验证码进行二值化.二.将二值化后的图片分割.三.进 ...
- python网络爬虫之如何识别验证码
有些网站的登录方式是验证码登录的方式,比如今天我们要测试的网站专利检索及分析. http://www.pss-system.gov.cn/sipopublicsearch/portal/uilogin ...
- Python 实现简单图片验证码登录
朋友说公司要在测试环境做接口测试,登录时需要传入正确的图片的验证码,本着懒省事的原则,推荐他把测试环境的图片验证码写死,我们公司也是这么做的^_^.劝说无果/(ㄒoㄒ)/~~,只能通过 OCR 技术来 ...
随机推荐
- photoSwiper移动端图片双击手势缩放
首先引入几个文件: <link rel="stylesheet" type="text/css" href="css/photoswipe.cs ...
- docker 开发常用命令总结
Docker 常用命令总结,镜像下载,到docker容器创建,常用docker命令的 增删查 1.镜像下载,从hub.docker.com中下载最新版本的postgres docker pull po ...
- ActiveReports 报表控件V12新特性 -- 新增JSON和CSV导出
ActiveReports是一款专注于 .NET 平台的报表控件,全面满足 HTML5 / WinForms / ASP.NET / ASP.NET MVC / WPF 等平台下报表设计和开发工作需求 ...
- 修复vs2012出现 “无法找到包源”的错误
出现以上问题,需要去“控制面板”添加程序,找到vs2012右键“修改” 用来安装 web Developer 如下图所示: 点击继续
- OpenCV 图形变换
1.图片缩小 matScale=np.float32([[0.5,0,0],[0,0.5,0]]) dst=cv2.warpAffine(img,matScale,(int(height/2),int ...
- [iOS]圆形进度条及计时功能
平时用战网安全令的时候很喜欢圆形倒计时的效果,然后简单看了一下Android的圆形进度条,后来又写了一个IOS的.整体界面参照IOS系统的倒计时功能,顺便熟悉了UIPickerView的一些特性的实现 ...
- 开发之道——读《移山之道——VSTS开发之道》后感
开发之道——读<移山之道——VSTS开发之道>后感 <移山之道——VSTS开发之道>(下简称<移山之道>)是邹欣老师的另一本书.相传很有名的<构建之法> ...
- 使用FireFox插件RESTClient、HttpRequester模拟http(get post)请求
我们写好一个接口后,需要进行测试.有时我们会写一个html表单提交,无疑增加了工作量,尤其是当参数比较多或者传json或xml数据时,效率更是大大降低.我们可以使用基于FireFox的RESTClie ...
- c#经典算法之冒泡排序(Bubble Sort)
转载于:https://www.cnblogs.com/shen-hua/p/5422676.html 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面, ...
- vscode 折叠所有区域代码的快捷键
折叠:ctrl + L ctrl + 0(主键盘区的0,不是小键盘区的0) 展开:ctrl + K ctrl + J 老是忘记,在此记录