第十篇:《自动化处理验证码:OCR、接口绕过与第三方服务》

验证码是UI自动化测试中最常见也最令人头疼的障碍。无论是图形验证码、滑块验证码还是短信验证码,传统脚本难以直接处理。本文将系统介绍多种解决方案:从OCR识别、模拟轨迹到更可靠的测试环境屏蔽、万能码、接口打桩,以及第三方打码平台。读完你将能根据项目情况选择最合适的验证码处理策略。

一、验证码的类型与挑战

核心原则:在测试环境中,尽量避免使用真实验证码算法。 最可靠的方法是让开发提供"测试模式"。

二、方案一:测试环境屏蔽验证码(最推荐)

与开发团队协商,在测试环境中:

固定一个万能码,如888888

注释掉验证码校验逻辑(仅测试环境)

通过特殊请求头或参数绕过

实现方式:

java 复制代码
// 后端伪代码(测试环境)
if ("test".equals(env) && inputCode.equals("888888")) {
    return success;
}

优点:100%稳定,无需额外代码。

缺点:需要开发和运维配合,可能影响验证码功能的回归测试。

三、方案二:OCR识别图形验证码

对于简单、无噪点、无干扰线的数字字母验证码,可以使用OCR(光学字符识别)库。

3.1 Java + Tesseract

依赖:

xml 复制代码
<dependency>
    <groupId>net.sourceforge.tess4j</groupId>
    <artifactId>tess4j</artifactId>
    <version>5.4.1</version>
</dependency>

需要下载Tesseract语言包(如eng.traineddata)并设置环境变量或指定路径。

代码示例:

java 复制代码
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import javax.imageio.ImageIO;
import java.io.File;
import java.awt.image.BufferedImage;

public class CaptchaOCR {
    public static String recognizeCaptcha(WebDriver driver, By captchaImgLocator) {
        // 获取验证码图片元素
        WebElement imgElement = driver.findElement(captchaImgLocator);
        // 截取图片
        File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        // 定位图片位置和大小
        Point point = imgElement.getLocation();
        Dimension size = imgElement.getSize();
        BufferedImage fullImg = ImageIO.read(screenshot);
        BufferedImage captchaImg = fullImg.getSubimage(point.getX(), point.getY(), size.getWidth(), size.getHeight());
        // 保存临时文件
        File tempFile = new File("captcha.png");
        ImageIO.write(captchaImg, "png", tempFile);
        
        // OCR识别
        Tesseract tesseract = new Tesseract();
        tesseract.setDatapath("C:/tesseract/tessdata"); // 设置tessdata路径
        tesseract.setLanguage("eng");
        tesseract.setTessVariable("tessedit_char_whitelist", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        try {
            String result = tesseract.doOCR(tempFile).replaceAll("\\s+", "");
            return result;
        } catch (TesseractException e) {
            e.printStackTrace();
            return "";
        } finally {
            tempFile.delete();
        }
    }
}

3.2 Python + pytesseract

安装:pip install pytesseract pillow,并安装Tesseract-OCR引擎(Windows需下载安装包,并配置路径)。

代码:

python 复制代码
import pytesseract
from PIL import Image
from selenium.webdriver.common.by import By

def recognize_captcha(driver, captcha_img_xpath):
    # 定位验证码图片元素
    img_elem = driver.find_element(By.XPATH, captcha_img_xpath)
    # 截图
    img_elem.screenshot("captcha.png")
    # OCR识别
    pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'  # Windows路径
    img = Image.open("captcha.png")
    code = pytesseract.image_to_string(img, config='--psm 8 -c tessedit_char_whitelist=0123456789')
    return code.strip()

提升识别率技巧:

对图片进行灰度化、二值化、去噪处理(使用OpenCV)

限制识别字符集(只识别数字和字母)

如果验证码固定长度(如4位),可以取前4个字符

局限性:复杂验证码(扭曲+干扰线+背景噪点)识别率很低,不建议依赖。

四、方案三:滑块验证码模拟

滑块验证码通常需要模拟人的拖动轨迹,包括加速、减速、停顿等特征。

核心思路:

获取滑块图片和背景缺口图片(或直接获取缺口位置)

计算需要滑动的距离(像素)

模拟鼠标滑动,轨迹符合人类行为

4.1 Python示例(使用OpenCV检测缺口位置)

python 复制代码
import cv2
import numpy as np
from selenium.webdriver.common.action_chains import ActionChains

def get_track(distance):
    """模拟人类滑动轨迹,返回位移列表"""
    track = []
    current = 0
    mid = distance * 4 / 5  # 前4/5加速,后1/5减速
    t = 0.2
    v = 0
    while current < distance:
        if current < mid:
            a = 2  # 加速
        else:
            a = -3  # 减速
        v0 = v
        v = v0 + a * t
        move = v0 * t + 0.5 * a * t * t
        current += move
        track.append(round(move))
    # 修正总距离误差
    total = sum(track)
    if total != distance:
        track.append(distance - total)
    return track

def slide_verify(driver, slider_xpath, distance):
    slider = driver.find_element(By.XPATH, slider_xpath)
    action = ActionChains(driver)
    action.click_and_hold(slider).perform()
    track = get_track(distance)
    for x in track:
        action.move_by_offset(xoffset=x, yoffset=0).perform()
    time.sleep(0.5)
    action.release().perform()

4.2 获取滑动距离的方法

通常需要两张图片:带缺口的背景图 + 滑块图。利用OpenCV的模板匹配识别缺口位置。

python 复制代码
def get_distance(bg_image_path, slider_image_path):
    bg = cv2.imread(bg_image_path, 0)
    slider = cv2.imread(slider_image_path, 0)
    # 模板匹配
    result = cv2.matchTemplate(bg, slider, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    # 缺口左上角x坐标
    return max_loc[0]

注意:滑块验证码的机制不断升级,模拟轨迹可能会被反爬检测到。测试环境建议直接绕过。

五、方案四:第三方打码平台

对于复杂验证码,可以使用专业打码平台(如超级鹰、打码兔)。这些平台提供API,发送验证码图片即可返回识别结果。

5.1 超级鹰API示例(Python)

注册并获取软件ID和密钥。示例代码:

python 复制代码
import requests
import base64

def chaojiying_captcha(img_path, codetype=1902):
    # codetype: 1902 表示4位英文数字
    url = "http://upload.chaojiying.net/Upload/Processing.php"
    with open(img_path, 'rb') as f:
        img_base64 = base64.b64encode(f.read()).decode('utf-8')
    data = {
        'user': 'your_username',
        'pass': 'your_password',
        'softid': 'your_softid',
        'codetype': codetype,
        'img_base64': img_base64
    }
    response = requests.post(url, data=data)
    return response.json()['pic_str'] if response.json()['err_no'] == 0 else None

5.2 优缺点

优点:可识别复杂验证码,适用性强。

缺点:

每次识别有成本(虽然很低)

网络请求有延迟

需要处理平台稳定性问题

六、方案五:短信/邮箱验证码

对于动态验证码,常见方案:

测试环境屏蔽:后端固定返回一个验证码(如123456)。

接码平台:for SMS,使用临时手机号接收验证码(不稳定,不推荐自动化)。

后端接口调用:测试框架调用内部接口查询发送的验证码(需要开发配合暴露接口)。

示例:后端提供一个查询最近验证码的接口,仅测试环境可用。

java 复制代码
// 测试代码中调用
String code = HttpUtil.get("http://internal-api/get-sms-code?phone=13800138000");
driver.findElement(By.id("smsCode")).sendKeys(code);

七、方案对比与选择建议

八、实战建议

对于正式UI自动化测试框架:

强烈建议:与开发团队沟通,在测试环境中添加"万能验证码"或屏蔽验证码校验。这是成本最低、最稳定的方案。

如果无法做到,可以尝试OCR+重试机制(识别失败刷新验证码)。

避免将复杂的滑块验证码自动化作为常规测试用例,维护成本过高。

一个通用的验证码处理流程:

java 复制代码
public String solveCaptcha(WebDriver driver, By imgLocator, int maxRetries) {
    for (int i = 0; i < maxRetries; i++) {
        String code = recognizeCaptcha(driver, imgLocator);
        if (code != null && code.length() >= 4) {
            return code;
        }
        // 识别失败,刷新验证码
        driver.findElement(By.id("refreshCaptcha")).click();
        Thread.sleep(1000);
    }
    throw new RuntimeException("验证码识别失败");
}

九、总结

核心原则:UI自动化测试的目标是验证业务功能,而不是测试验证码算法本身。因此,在非生产环境中绕过验证码是最佳实践。

相关推荐
qq_426003961 天前
启动playwright录制codegen生成自动化测试脚本
python·自动化
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
森叶1 天前
用远程调试端口自动化 Chrome 应用商店发布:做法、三个真坑,以及你必须知道的风险
自动化