| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- # -*- 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) # 一次性补
|