Skip to content

基于 OCR 识别方法的自动化测试


目录

  • 课程目标
  • 应用场景
  • OCR 文字识别与自动化测试

课程目标

  1. 掌握 自动化过程中验证码的获取方式。

  2. L1.用例录制与编写

  3. L2.高级定位与 PO 设计模式
  4. L3.webview 与微信小程序测试
  5. L4.Appium 源码分析与定制
  6. L5.分布式测试与多设备管理【当前阶段】

思考

自动化登录时验证码如何获取?


OCR 文字识别简介

  • 光符识别(optical character recognition)。
  • 对文本资料进行扫描,然后对图像文件进行分析处理,获取文字及版面信息的过程。


常见OCR识别第三方库

  • EasyOCR
    • 基于Tesseract的OCR识别库,用于图像识别输出文本,目前支持80多种语言。
    • 模型包含文本检测、文本识别功能。
  • MuggleOCR
    • 一款轻量级的ocr识别库,从名字也可以看出来,专为麻瓜设计。
    • 使用非常简单。
    • 主要是用于识别各类验证码,一般文字提取效果就稍差了。
  • ddddOCR
    • 一款用于识别验证码的开源库。
    • 对一些常规的数字、字母验证码识别有奇效

演练环境

  • 霍格沃兹测试开发学社演练环境:
    • https://vip.ceshiren.com/#/ui_study/code

实现思路

uml diagram


未使用 OCR 处理(Python)

  • Python 环境准备: pip install easyocr
# 不加 AI 处理的场景,无法拿到ocr数据,用例失败
    def test_code_by_ocr(self):
        # 获取验证码图片链接
        img_url = self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) img").get_attribute("src")
        # 获取验证码内容
        code = OcrCode.get_by_ocr(img_url)
        # 输入验证码
        self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) input").send_keys(code)
        # 点击确认
        self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) button").click()
        sleep(1)
        # 断言验证码是否正确
        text = self.driver.find_element(By.CSS_SELECTOR, ".el-message p").text
        print(text)
        assert text == "验证成功"

使用 EasyOCR 进行文字识别(Python)

# ocr_code.py
class OcrCode:

    @classmethod
    def get_by_ocr(cls, img_url):
        # 使用requests发请求拿到图片结果
        result = requests.get(img_url, verify=False)
        # 保存图片到本地
        with open("code.png", "wb") as f:
            f.write(result.content)
        sleep(1)
        # 实例化easyocr
        ocr = easyocr.Reader(['ch_sim', 'en'])
        # 识别图片内容,并去掉空格
        code = ocr.readtext("code.png")[0][1].replace(" ", "")
        print(f"识别到的验证码为:{code}")
        return code
# test_code.py
class TestCode:

    def setup_class(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(10)
        # 打开页面
        self.driver.get("https://vip.ceshiren.com/#/ui_study/code")

    def teardown_class(self):
        self.driver.quit()

    def test_code_by_ocr(self):
        # 获取验证码图片链接
        img_url = self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) img").get_attribute("src")
        # 获取验证码内容
        code = OcrCode.get_by_ocr(img_url)
        # 输入验证码
        self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) input").send_keys(code)
        # 点击确认
        self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) button").click()
        sleep(1)
        # 断言验证码是否正确
        text = self.driver.find_element(By.CSS_SELECTOR, ".el-message p").text
        print(text)
        assert text == "验证成功"

未使用 AI 处理(Java)

<!-- easyocr依赖 -->
<dependency>
    <groupId>cn.easyproject</groupId>
    <artifactId>easyocr</artifactId>
    <version>3.0.4-RELEASE</version>
</dependency>
    @Test
    public void codeByOcr() throws IOException, InterruptedException {
        // 获取验证码图片链接
        String imgUrl = driver.findElement(By.cssSelector(".code1:nth-child(1) img")).getAttribute("src");
        // 获取验证码内容
        String code = OcrCode.getByOcr(imgUrl);
        // 输入验证码
        driver.findElement(By.cssSelector(".code1:nth-child(1) input")).sendKeys(code);
        // 点击确认
        driver.findElement(By.cssSelector(".code1:nth-child(1) button")).click();
        sleep(1000);
        // 断言验证码是否正确
        String text = driver.findElement(By.cssSelector(".el-message p")).getText();
        System.out.println(text);
        assertNotEquals("验证成功", text);
    }

使用 EasyOCR 进行文字识别(Java)

// OcrCode.java
public class OcrCode {

    public static String getByOcr(String imgUrl) throws IOException {
        // 使用restassured发请求拿到图片结果
        Response response = given().get(imgUrl).then().extract().response();
        // 图片保存的目录和文件名
        File input = new File("code.png");
        FileOutputStream fos = new FileOutputStream(input);
        // 将图片保存到文件
        fos.write(response.getBody().asByteArray());
        fos.close();
        EasyOCR e=new EasyOCR();
        //直接识别图片内容
        String code = e.discern(input);
        System.out.println(code);
        return code;
    }
}
// CodeTest.java
class CodeTest {

    public static ChromeDriver driver;

    @BeforeAll
    public static void beforeAll() {
        ChromeOptions option = new ChromeOptions();
        option.addArguments("--remote-allow-origins=*");
        driver = new ChromeDriver(option);
        // 隐式等待
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://vip.ceshiren.com/#/ui_study/code");
    }

    @AfterAll
    public static void afterAll() {
        driver.quit();
    }

    @Test
    public void codeByOcr() throws IOException, InterruptedException {
        // 获取验证码图片链接
        String imgUrl = driver.findElement(By.cssSelector(".code1:nth-child(1) img")).getAttribute("src");
        // 获取验证码内容
        String code = OcrCode.getByOcr(imgUrl);
        // 输入验证码
        driver.findElement(By.cssSelector(".code1:nth-child(1) input")).sendKeys(code);
        // 点击确认
        driver.findElement(By.cssSelector(".code1:nth-child(1) button")).click();
        sleep(1000);
        // 断言验证码是否正确
        String text = driver.findElement(By.cssSelector(".el-message p")).getText();
        System.out.println(text);
        assertNotEquals("验证成功", text);
    }
}


总结


源码地址


附录:完整依赖配置(Python)

async-generator==1.10
attrs==23.1.0
certifi==2022.12.7
cffi==1.15.1
charset-normalizer==3.1.0
colorama==0.4.6
easyocr==1.6.2
exceptiongroup==1.1.1
filelock==3.12.0
h11==0.14.0
idna==3.4
imageio==2.28.1
iniconfig==2.0.0
Jinja2==3.1.2
lazy_loader==0.2
MarkupSafe==2.1.2
mpmath==1.3.0
networkx==3.1
ninja==1.11.1
numpy==1.24.3
opencv-python-headless==4.5.4.60
outcome==1.2.0
packaging==23.1
Pillow==9.5.0
pluggy==1.0.0
pyclipper==1.3.0.post4
pycparser==2.21
PySocks==1.7.1
pytest==7.3.1
python-bidi==0.4.2
PyWavelets==1.4.1
PyYAML==6.0
requests==2.28.2
scikit-image==0.20.0
scipy==1.10.1
selenium==4.9.0
shapely==2.0.1
six==1.16.0
sniffio==1.3.0
sortedcontainers==2.4.0
sympy==1.11.1
tifffile==2023.4.12
tomli==2.0.1
torch==2.0.0
torchvision==0.15.1
trio==0.22.0
trio-websocket==0.10.2
typing_extensions==4.5.0
urllib3==1.26.15
wsproto==1.2.0


附录:完整依赖配置(Java)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>javaProject</artifactId>
        <groupId>com.ceshiren</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>PictureCode</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--junit5-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <!--对应添加的依赖的作用范围-->
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <scope>test</scope>
        </dependency>

        <!--hamcrest断言-->
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest</artifactId>
            <version>2.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <version>2.2</version>
            <scope>test</scope>
        </dependency>

        <!-- selenium-->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.3.0</version>
        </dependency>

        <!-- rest-assured -->
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>4.4.0</version>
            <scope>compile</scope>
        </dependency>

        <!-- easyocr依赖 -->
        <dependency>
            <groupId>cn.easyproject</groupId>
            <artifactId>easyocr</artifactId>
            <version>3.0.4-RELEASE</version>
        </dependency>
    </dependencies>

</project>