技术栈

组件 方案
验证码识别 ddddocr
并发框架 concurrent.futures.ThreadPoolExecutor
代理池 自建 Flask 代理分发服务
随机账号 faker
结果存储 CSV 文件

安装依赖

pip install ddddocr faker requests

ddddocr 安装时会下载 ONNX 模型文件,首次安装较慢。

验证码识别

import ddddocr, requests, base64

ocr = ddddocr.DdddOcr(show_ad=False)

def get_captcha_text(session: requests.Session) -> tuple[str, str]:
    # 获取验证码图片并识别,返回 (验证码文本, 验证码ID)
    # 1. 请求验证码图片
    r = session.get(
        "https://ptlogin.4399.com/captcha/get",
        params={"r": str(time.time())},
        timeout=10
    )
    data = r.json()
    captcha_id = data.get("captchaId", "")
    img_b64 = data.get("img", "")  # base64 图片

    # 2. 识别
    img_bytes = base64.b64decode(img_b64)
    text = ocr.classification(img_bytes)
    return text.strip(), captcha_id

随机账号生成

from faker import Faker
import random, string

fake = Faker("zh_CN")

def gen_username() -> str:
    # 生成随机用户名(中文拼音 + 数字混合)
    prefix = fake.user_name()[:8]
    suffix = "".join(random.choices(string.digits, k=4))
    return f"{prefix}{suffix}"

def gen_password(length: int = 12) -> str:
    # 生成符合规则的随机密码
    chars = string.ascii_letters + string.digits + "!@#$"
    while True:
        pwd = "".join(random.choices(chars, k=length))
        # 确保包含大写、小写、数字、特殊字符
        if (any(c.isupper() for c in pwd) and
            any(c.islower() for c in pwd) and
            any(c.isdigit() for c in pwd)):
            return pwd

注册核心逻辑

import requests, time

REGISTER_URL = "https://ptlogin.4399.com/register"

def register_one(proxy: str = None) -> dict:
    # 注册一个账号,返回结果
    session = requests.Session()
    if proxy:
        session.proxies = {
            "http": f"http://{proxy}",
            "https": f"http://{proxy}"
        }

    username = gen_username()
    password = gen_password()

    # 1. 获取并识别验证码
    try:
        captcha_text, captcha_id = get_captcha_text(session)
    except Exception as e:
        return {"status": "captcha_error", "error": str(e)}

    # 2. 提交注册
    payload = {
        "username": username,
        "password": password,
        "password2": password,
        "captcha": captcha_text,
        "captchaId": captcha_id,
        "agreement": "1",
    }
    try:
        r = session.post(REGISTER_URL, data=payload, timeout=15)
        data = r.json()
        if data.get("code") == 0:
            return {"status": "ok", "username": username, "password": password}
        else:
            return {"status": "fail", "msg": data.get("msg"), "username": username}
    except Exception as e:
        return {"status": "error", "error": str(e)}

多线程并发

from concurrent.futures import ThreadPoolExecutor, as_completed
import csv, threading

MAX_WORKERS = 30
results_lock = threading.Lock()
success_count = 0
fail_count = 0

def batch_register(target: int = 100, proxy_pool=None):
    global success_count, fail_count
    rows = []

    def task():
        proxy = proxy_pool.get() if proxy_pool else None
        result = register_one(proxy)
        if proxy_pool and result["status"] != "ok" and proxy:
            proxy_pool.remove(proxy)  # 代理失效则移除
        return result

    with ThreadPoolExecutor(max_workers=MAX_WORKERS) as pool:
        futures = [pool.submit(task) for _ in range(target)]
        for i, f in enumerate(as_completed(futures), 1):
            result = f.result()
            with results_lock:
                if result["status"] == "ok":
                    success_count += 1
                    rows.append(result)
                    print(f"[{i}/{target}] ✓ {result['username']}")
                else:
                    fail_count += 1
                    print(f"[{i}/{target}] ✗ {result.get('msg', result.get('error', ''))}")

    # 保存成功账号
    if rows:
        with open("accounts.csv", "a", newline="", encoding="utf-8-sig") as f:
            writer = csv.DictWriter(f, fieldnames=["username", "password", "status"])
            writer.writerows(rows)
    print(f"
完成成功 {success_count}失败 {fail_count}")

ddddocr 识别率优化

ddddocr 对常见字符验证码准确率约 85-92%,可以通过以下方式提升:

  1. 多次识别取最多数:对同一验证码图片识别3次,取出现最多的结果
from collections import Counter

def robust_ocr(img_bytes: bytes, n: int = 3) -> str:
    results = [ocr.classification(img_bytes) for _ in range(n)]
    return Counter(results).most_common(1)[0][0]
  1. 失败重试:识别失败或注册返回验证码错误时,自动重新获取验证码
def register_with_retry(proxy=None, max_retry=3) -> dict:
    for _ in range(max_retry):
        result = register_one(proxy)
        if result["status"] == "ok":
            return result
        if "验证码" in result.get("msg", ""):
            time.sleep(0.5)
            continue
        break
    return result

效果数据

配置 目标数量 耗时 成功率
30线程,无代理 100 ~45秒 约78%
30线程,代理池 100 ~60秒 约85%
10线程,代理池 50 ~40秒 约91%

免责声明:本文仅供学习验证码识别技术,请遵守目标网站服务条款。