接口测试 来点高级货:手搓自动化验证码登录注册自动化测试

NiMail · 2025年10月27日 · 最后由 Cindylong 回复于 2025年10月28日 · 1420 次阅读

以前提到验证码注册登录自动化问题就堵死,也确实是,问题不是在于技术难度,代码难写,而是在于没有验证码接口呀,巧妇难为无米之炊!

现在我自己手搓了一个邮件服务接口,直接提供验证码查询 API 出来。

当前的思路是这样,我下面直接输出接口代码:

第一步:随机一个 https://www.nimai.cn 的临时邮箱(如:x2sd332@nimail.cn),调用业务接口,发送验证码:

第二步 1:查询邮件服务接口,用上面随机生成的邮箱(x2sd332@nimail.cn)去循环查询邮件。
关键在这里,需要用邮箱去查邮件,这里可能返回多个邮件,拿最新的一个就行:
curl 'https://www.nimail.cn/api/getmails' \
-H 'accept: application/json, text/javascript, /; q=0.01' \
-H 'accept-language: zh-CN,zh;q=0.9' \
-H 'origin: https://www.nimail.cn' \
--data-raw 'mail=ohgim96m%40nimail.cn'

第二步 2:上面查询到数据后,使用字段 id 的值,请求这个接口获取邮件内容。
curl 'https://www.nimail.cn/api/raw-html/ohgim96m@nimail.cn/1761577116655'

第三步:查询到的邮件后,对邮件进行正则匹配,匹配到你的验证码,提取出来。

第四步:用验证码和第一步调用业务接口获取到的随机字符串一起,请求验证接口或者注册接口

第五步:验证完成。

代码示例如下:

import requests
import random
import string
import time
import re
import json
import urllib.parse

class EmailVerification:
    def __init__(self):
        self.base_url = "http://localhost:8888/v1/user"
        self.nimail_api = "https://www.nimail.cn/api"

    def generate_random_email(self):
        """生成随机nimail邮箱"""
        # 生成随机用户名(6-10位字母数字)
        username_length = random.randint(6, 10)
        username = ''.join(random.choices(string.ascii_lowercase + string.digits, k=username_length))

        return f"{username}@nimail.cn"

    def send_verification_code(self, email):
        """第一步:发送验证码"""
        url = f"{self.base_url}/sendEmailCode"

        headers = {
            'Accept-Language': 'en-US',
            'Content-Type': 'text/plain'
        }

        data = {
            "email": email
        }

        try:
            response = requests.post(url, headers=headers, data=json.dumps(data))
            print(f"发送验证码响应状态: {response.status_code}")
            print(f"发送验证码响应内容: {response.text}")

            if response.status_code == 200:
                # 假设响应中包含codeid,根据实际接口调整
                response_data = response.json()
                codeid = response_data.get('codeid', 'default_codeid')
                return True, codeid
            else:
                return False, None

        except Exception as e:
            print(f"发送验证码时出错: {e}")
            return False, None

    def get_emails_list(self, email, max_attempts=30, delay=2):
        """第二步1:查询邮件列表"""
        print(f"开始查询邮箱 {email} 的邮件列表...")

        for attempt in range(max_attempts):
            try:
                headers = {
                    'accept': 'application/json, text/javascript, */*; q=0.01',
                    'accept-language': 'zh-CN,zh;q=0.9',
                    'origin': 'https://www.nimail.cn'
                }

                # 构建请求数据
                data = {
                    'mail': email
                }

                response = requests.post(f"{self.nimail_api}/getmails", headers=headers, data=data)

                if response.status_code == 200:
                    emails_data = response.json()

                    # 根据实际API响应结构调整
                    if isinstance(emails_data, list) and len(emails_data) > 0:
                        print(f"第 {attempt + 1} 次查询: 找到 {len(emails_data)} 封邮件")
                        # 返回最新的邮件(假设列表是按时间顺序的,第一个或最后一个是最新的)
                        latest_email = emails_data[0]  # 根据实际情况调整索引
                        return latest_email
                    else:
                        print(f"第 {attempt + 1} 次查询: 未找到邮件,继续等待...")
                else:
                    print(f"第 {attempt + 1} 次查询: API响应异常,状态码: {response.status_code}")

            except Exception as e:
                print(f"第 {attempt + 1} 次查询时出错: {e}")

            time.sleep(delay)

        print("达到最大查询次数,未找到验证码邮件")
        return None

    def get_email_content(self, email, email_id):
        """第二步2:根据邮件ID获取邮件内容"""
        try:
            # 构建获取邮件内容的URL
            url = f"{self.nimail_api}/raw-html/{urllib.parse.quote(email)}/{email_id}"

            headers = {
                'accept': 'application/json, text/javascript, */*; q=0.01',
                'accept-language': 'zh-CN,zh;q=0.9',
                'origin': 'https://www.nimail.cn'
            }

            response = requests.get(url, headers=headers)

            if response.status_code == 200:
                print("成功获取邮件内容")
                return response.text
            else:
                print(f"获取邮件内容失败,状态码: {response.status_code}")
                return None

        except Exception as e:
            print(f"获取邮件内容时出错: {e}")
            return None

    def extract_verification_code(self, email_content):
        """第三步:从邮件内容中提取验证码"""
        if not email_content:
            return None

        # 使用正则表达式匹配验证码(6位数字)
        code_patterns = [
            r'\b\d{6}\b',  # 6位数字
            r'验证码.*?(\d{6})',  # 包含"验证码"的6位数字
            r'code.*?(\d{6})',  # 包含"code"的6位数字
            r'verification.*?(\d{6})',  # 包含"verification"的6位数字
            r'【.*?】.*?(\d{6})',  # 中文格式的验证码
            r'<strong>(\d{6})</strong>',  # HTML中的验证码
            r'<td[^>]*>(\d{6})</td>'  # 表格中的验证码
        ]

        for pattern in code_patterns:
            matches = re.search(pattern, email_content, re.IGNORECASE)
            if matches:
                verification_code = matches.group(1) if matches.groups() else matches.group(0)
                print(f"找到验证码: {verification_code}")
                return verification_code

        # 如果没有匹配到,尝试打印部分内容用于调试
        print("邮件内容预览(前500字符):", email_content[:500])
        print("未在邮件中找到验证码")
        return None

    def register_user(self, email, codeid, verification_code, password="123456"):
        """第四步:注册用户"""
        url = f"{self.base_url}/register"

        headers = {
            'Content-Type': 'text/plain'
        }

        data = {
            "username": email,
            "account": "",
            "password": password,
            "codeid": codeid,
            "code": int(verification_code)
        }

        try:
            response = requests.post(url, headers=headers, data=json.dumps(data))
            print(f"注册响应状态: {response.status_code}")
            print(f"注册响应内容: {response.text}")

            if response.status_code == 200:
                print("注册成功!")
                return True
            else:
                print("注册失败!")
                return False

        except Exception as e:
            print(f"注册时出错: {e}")
            return False

    def run_complete_verification(self):
        """执行完整的验证流程"""
        print("=== 开始邮箱验证流程 ===")

        # 第一步:生成随机邮箱并发送验证码
        email = self.generate_random_email()
        print(f"生成的随机邮箱: {email}")

        success, codeid = self.send_verification_code(email)
        if not success:
            print("发送验证码失败,终止流程")
            return False

        print(f"验证码发送成功,codeid: {codeid}")

        # 第二步1:查询邮件列表,获取最新邮件
        latest_email = self.get_emails_list(email)
        if not latest_email:
            print("未找到邮件,终止流程")
            return False

        # 获取邮件ID(根据实际API响应结构调整)
        email_id = latest_email.get('id')
        if not email_id:
            print("未找到邮件ID,终止流程")
            return False

        print(f"找到最新邮件,ID: {email_id}")

        # 第二步2:获取邮件内容
        email_content = self.get_email_content(email, email_id)
        if not email_content:
            print("获取邮件内容失败,终止流程")
            return False

        # 第三步:提取验证码
        verification_code = self.extract_verification_code(email_content)
        if not verification_code:
            print("未找到验证码,终止流程")
            return False

        # 第四步:注册用户
        success = self.register_user(email, codeid, verification_code)

        # 第五步:完成验证
        if success:
            print("=== 验证完成 ===")
        else:
            print("=== 验证失败 ===")

        return success

# 使用示例
if __name__ == "__main__":
    verifier = EmailVerification()

    # 执行一次完整的验证流程
    verifier.run_complete_verification()

    # 如果需要批量执行,可以使用循环
    # for i in range(5):  # 执行5次
    #     print(f"\n=== 第 {i+1} 次执行 ===")
    #     verifier.run_complete_verification()
    #     time.sleep(5)  # 每次执行间隔5秒
共收到 5 条回复 时间 点赞

666666666666666666666

优秀👍👍

我刚遇到这个问题,现在就看到这个文章,太好了,赶紧去试试

Cindylong 回复

有问题随时可以贴出来哦,互相学习一起进步

回复内容未通过审核,暂不显示
需要 登录 後方可回應,如果你還沒有帳號按這裡 注册