第十篇:《自动化处理验证码: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自动化测试的目标是验证业务功能,而不是测试验证码算法本身。因此,在非生产环境中绕过验证码是最佳实践。

相关推荐
Agent产品评测局2 小时前
制造业生产调度自动化落地,完整步骤与避坑指南:2026企业级智能体选型与实战全景
运维·人工智能·ai·chatgpt·自动化
a8a3022 小时前
Laravel 10.x核心特性深度解析
android
志栋智能2 小时前
超自动化巡检:让合规与审计变得轻松简单
运维·网络·人工智能·自动化
好度3 小时前
自动化教程-封装浏览器驱动
运维·自动化
angerdream4 小时前
Android手把手编写儿童手机远程监控App之UUID
android
dalancon4 小时前
Android OomAdjuster流程
android
河婆墟邓紫棋4 小时前
MIUI中的权限
android·github
我命由我123456 小时前
Java 开发 - CountDownLatch 不需要手动关闭
android·java·开发语言·jvm·kotlin·android studio·android-studio
众少成多积小致巨6 小时前
GNU Make 核心指南
android·c++