# -*- coding: utf-8 -*- # Author : Charley # Python : 3.12.10 # Date : 2026/09/09 """账号池一键补号脚本(经接码平台自动注册 = 登录即注册)。 用法: python spiders/replenish_accounts.py # 默认单次最多补 5 个(分天补,降连坐) python spiders/replenish_accounts.py --batch 3 # 本次最多补 3 个 python spiders/replenish_accounts.py --target 20 --batch 20 # 补满 20(⚠️ 一次爆量连坐风险高) python spiders/replenish_accounts.py --loop # 常驻定时模式:每 2h 巡检补一次(供 start_all 长跑) 补货前会先释放 dead 号占用的专属 IP(不复活、仅回收 IP),故 dead 掉号后 healthy 能自动被新号补回。 风控提醒:得卡强风控,短时间同机批量注册新号是最典型连坐信号。默认单次限 5 个、每号错峰 30~90s,建议分几天补满 POOL_TARGET_SIZE(20),让号陆续自然增长,别一次爆量。 """ # ---------- bootstrap:定位新根 + 挂 common 到 sys.path + chdir 新根(共用根 application.yml/logs)---------- import os import sys _ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(_ROOT, "common")) os.chdir(_ROOT) import argparse import time import schedule from loguru import logger from mysql_pool import MySQLConnectionPool from account_pool import AccountPool, POOL_TARGET_SIZE # 定时模式默认巡检间隔(小时):常驻跑时每隔 N 小时补一次;只在 healthy 不足时才真买号,够用即空跑 REPLENISH_EVERY_HOURS = 2 # 日志:按天切分,保留 7 天 logger.remove() logger.add(sys.stderr, format="[{time:HH:mm:ss}] {level} {message}", level="INFO") logger.add("./logs/replenish_{time:YYYYMMDD}.log", encoding="utf-8", rotation="00:00", format="[{time:YYYY-MM-DD HH:mm:ss}] {level} {message}", level="INFO", retention="7 day") def main(target: int, batch: int) -> None: """补号主流程:把账号池 healthy 数补到 target,单次最多补 batch 个。 Args: target (int): 账号池目标 healthy 数(补到此值为止)。 batch (int): 本次运行最多新增几个号(分批/分天控节奏、降连坐)。 """ pool = MySQLConnectionPool(log=logger) if not pool.check_pool_health(): logger.error("数据库连接池异常,退出") return ap = AccountPool(pool, log=logger, task_tag="replenish") ap.revive_cooling() # 先把冷却(cooling)到期的号恢复 healthy,再统计是否需补(避免多注册) cur = ap.count_healthy() # 单次限量:本次目标 = min(总目标, 当前 + batch),避免一次爆量 run_target = min(target, cur + batch) logger.info(f"补号开始:当前 healthy={cur},总目标={target},本次补到={run_target}(单次限 {batch} 个)") if cur >= run_target: logger.info("已达标,无需补货") return added = ap.auto_replenish(target_min=run_target, target_max=run_target) logger.info(f"补号结束:本次新增 {added} 个,当前 healthy={ap.count_healthy()}(总目标 {target})") def schedule_loop(target: int, batch: int, hours: int) -> None: """常驻定时补号:先立即补一次,之后每 hours 小时巡检补一次(供 start_all 拉起长跑)。 每轮内部会先释放 dead 号占用的专属 IP 再补(见 AccountPool.auto_replenish),故 dead 号 掉了也能被新号顶替、healthy 自动回到 target;只在 healthy < 目标时才真向接码平台买号。 Args: target (int): 账号池目标 healthy 数。 batch (int): 单轮最多新增几个号(分批错峰、降连坐)。 hours (int): 巡检间隔小时数。 """ logger.info(f"账号池自动补货常驻启动:每 {hours} 小时巡检一次,目标 {target},单轮限 {batch} 个") main(target=target, batch=batch) # 启动即补一次,先把当前缺口补上 schedule.every(hours).hours.do(main, target=target, batch=batch) while True: schedule.run_pending() time.sleep(1) if __name__ == "__main__": parser = argparse.ArgumentParser(description="账号池一键补号(接码平台自动注册)") parser.add_argument("--target", type=int, default=POOL_TARGET_SIZE, help=f"池子总目标数,默认 {POOL_TARGET_SIZE}") parser.add_argument("--batch", type=int, default=5, help="单次/单轮最多补几个(分批降连坐),默认 5") parser.add_argument("--loop", action="store_true", help="常驻定时模式:每 --hours 小时巡检补一次(供 start_all 长跑)") parser.add_argument("--hours", type=int, default=REPLENISH_EVERY_HOURS, help=f"定时模式巡检间隔小时,默认 {REPLENISH_EVERY_HOURS}") args = parser.parse_args() if args.loop: schedule_loop(target=args.target, batch=args.batch, hours=args.hours) # 常驻定时 else: main(target=args.target, batch=args.batch) # 一次性补