账号池落地_得卡DECA_20260909.md 14 KB

得卡 DECA 账号池落地文档

落地日期:2026/09/09 | 运行环境:Python 3.12.10 代码位置:common/account_pool.py(账号池)、common/deca_account_ddl.sql(建表)、common/deca_sold_core.py(采集核心 + step3 接入) 事实台账:HANDOFF.md(新窗口接手先读它,进度以其为准)


1. 背景与目标

原采集把所有登录态集中在单账号 + 单 token.json:一个得卡账号扛全部带 token 请求(约 4 万/天,几乎全压夜间 20:00~06:00)。一旦这个账号被风控击穿,整条采集链全停(2026/09/07 即因此停摆)。

账号池目标:多账号入池、按任务随机取号、异常自动切号、把请求量摊平到多账号 + 各账号专属静态 IP,从根上消除「单账号单点」风险,降低单号风控面。


2. 整体架构

采集脚本(buy_record/sold/team/onsale_alert/在售报告)
        │  do_request(need_auth=True)
        ▼
deca_sold_core(签名 / 请求 / step3 账号池接入)
        │  USE_ACCOUNT_POOL=True 时
        ▼
AccountPool(common/account_pool.py)
        │  acquire_random → ensure_access → 该号专属 proxy_url
        ▼
deca_account_record 表(多账号:token / 状态 / 专属 IP / 租约)
  • 默认关USE_ACCOUNT_POOL=False,采集走老单 token.json;采集入口调 core.init_account_pool(pool) 才切到账号池。
  • 每个常驻任务进程持一个 AccountPool 实例,进程内单例。

3. 数据模型:deca_account_record

DDL 见 common/deca_account_ddl.sql,已在 100.64.0.25/crawler 建好(20 列)。要点:

  • 自增 id 物理主键;phone 单独建 UNIQUE(业务唯一标识);时间字段固定 gmt_create_time/gmt_modified_time
  • 每号独立 access_token/refresh_token/token_exp
  • proxy_url:该号绑定的专属静态出口 IP(1 号 1 IP 永久绑定,必须静态独享,勿用隧道)。
  • status 三态:healthy(可用)/ cooling(软风控冷却)/ dead(登录态死,需人工补货)。
  • owner_pid/lease_until:进程独占租约(进程崩溃后租约到期自动可再租,不死占)。
  • fail_count/cooldown_until/last_used_at/last_success_at/last_error:状态机与排障字段。

4. 账号供给:短信验证码登录 =「登录即注册」

得卡无独立注册接口——新手机号首次短信验证码登录即自动开户。故供给(注册新号 / 补货已死号)统一走短信登录。

接口(抓包 抓包.txt,签名与 make_signature 一致,已核验命中):

接口 路径 body 说明
发验证码 /api/v1/app/auth/sms/send {countryCode, phone} need_auth=False
短信登录 /api/v1/app/auth/sms/login {countryCode, phone, code} need_auth=False,返回 accessToken/refreshToken/expiresIn/userId

AccountPool 方法:

  • sms_send(phone):发验证码(登录/注册第一步)。
  • sms_login(phone, code, proxy_url=None, password=None):短信登录并入库。新号 INSERT、已存在号(补货)UPDATEON DUPLICATE KEYproxy_urlCOALESCE 不覆盖已绑定 IP),成功即置 healthy、清租约。
  • register(phone, code, ...):等价 sms_login(两步:先 sms_send 收码,再带 code 调用)。

密码登录 _login() 保留作极端兜底,线上默认不调(撞阿里云滑块,无人值守过不去)。短信登录不撞滑块,是补货/开户主路径。


5. 取号策略:每批随机(默认)+ 独占(保留)

  • acquire_random(lease_sec=300):从 healthyRAND() 随机挑一个未被占的号,带「仍空闲」条件 UPDATE 认领(防并发抢占),打短租约每批随机主路径。
  • acquire():进程级独占(按 last_used_at 升序负载均衡),整运行期独占一个号。保留可选。
  • switch() / release():换号 / 归还租约。

为什么每批随机:把带 token 请求量摊平到所有号,单号日请求量大降、风控面更小。只要每个号的请求始终走它自己的 proxy_url,「账号↔IP 绑定」不破——随机的是「派哪个号上」,不是「一个号在多 IP 间跳」。

短租约的作用:批期间对该号的续期串行化,避免多进程同时选中同号并发踩废「一次性轮换」的 refreshToken


6. Token 续期与判死(实测)

  • ensure_access(log):access 未临期直接返回缓存;临期用该号 refresh 续签并回写 DB(access/refresh/token_exp/fail_count)。线上只 refresh、不自动密码登录
  • 续期一次性轮换:续签成功即发新 refresh、旧的立即作废。多进程共用 token.json 时代靠 .lock 串行化;账号池每号独立,靠短租约 + acquire_random 抢占避免并发。

判死码(2026/09/09 实测,测试号 19521500850 直连)

refresh 失效时服务端返回:

code = 10010
msg  = 当前账号长期未登录,请重新登录

涵盖「refresh 被轮换 / 过期 / 长期未登录」。写进 account_pool.DEAD_CODES = {10010}

  • ensure_access 续签命中 10010report_failure(dead=True),直接判 dead 摘池(线上不自动登录);
  • 其他未知码 → 按软失败累计(可能限流/网络,不急着判死),达 MAX_FAIL(3)cooling

7. 保活决策:不加主动保活(2026/09/09 定)

  • 关键区分:access 15 分钟过期,用时续签即可;真正决定账号存活的是 refresh 会不会因「长期不用」失效。
  • 依据:既往经验——sold 任务每天仅跑 1 次(间隔 ~24h)一直能正常续签 → refresh 失效阈值 > 24h(很可能数天)。
  • 结论:随机取号下只要一个号「至少每天被用到一次」就不会饿死;20 号 + 每批随机,单号日内被选中概率高。不加定时保活,靠既有容错兜底:用时续签 + 续签命中 10010 自动判 dead 切号 + 企微通知人工补货。比定时保活更省更简单。

8. step3:采集接入(deca_sold_core core 侧改造)

need_auth 请求的取 token 从「单 token.json」切到「账号池」。2026/09/09 完成并端到端验证通过(测试号跑通商家列表 code=0)。

新增函数(deca_sold_core.py):

  • init_account_pool(pool, task_tag="core", rotate_every=20)启用入口,采集脚本启动调一次,置 USE_ACCOUNT_POOL=True
  • rotate_account(log):批边界主动随机换号(如每商家开始)。
  • release_account():归还当前号。
  • _pool_auth_and_proxy(log):取「当前号有效 access + 该号专属 proxies」,每 rotate_every 个请求自动随机换号,续签失败自动换号重试。

do_request/do_getneed_auth 分支:启用后走账号池,请求走该号专属 proxy_url(为空=直连,IP 填了自动生效);未启用走老 ensure_token

每批随机的实现:默认每 rotate_every=20need_auth 请求自动随机换一次号,无需改采集脚本;也可在明确批边界调 rotate_account() 强制换。

采集脚本如何启用(上线时做)

在各采集入口 main 开头加一行:

core.init_account_pool(pool, task_tag="buy_record:881226408")  # 不加则维持老单 token.json

9. 长效 IP 选型(2026/09/09 实测)

核心原则:对得卡(国内卡片交易平台,用户全在国内),IP 地理位置(国内)比 IP 类型(住宅 vs 机房)更重要——异地(尤其海外)IP 是最强风控信号之一。

候选 地理 类型 独占性 对得卡
123proxy 北美(实测 76.46.19.42 美国·辛辛那提·Charter 住宅) 🔴 美国 🟢 住宅 独享 异地风控高危 + 延迟 3.9s,不推荐
快代理独享版 🟢 国内 🟡 机房 完全独享 地理对、类型略可疑,可用
快代理共享版 🟢 国内 🟡 机房 与少数客户共用 有连坐风险,概率可控
理想 🟢 国内 🟢 住宅/静态 独享 最优

决策进展:先买快代理共享版 1 个月试(成本低,稳则用、不稳再上独享池)。

  • ⚠️ 购买前必须向客服确认「共享版分配的 IP 是固定不变的吗」——固定才能绑定;动态轮换(≈隧道)不可用。
  • 落地:拿到 IP 后先只绑测试号 id=1 的 proxy_url 跑几天,观察 ①得卡认不认该 IP ②号会不会判死(10010=连坐信号);稳则扩量。
  • 持续监控信号:「同一 IP 上多个号集体判死」= 该 IP 被关联,立即换独享池。

9.5 自动补货(接码平台爱接码 i-sms.app,框架已落地)

账号池巡检可用号数,不足阈值时全自动经接码平台注册补充(登录即注册),无需人工收码。

  • 接码平台:爱接码 https://www.i-sms.app,鉴权 X-API-KEY(环境变量 ISMS_API_KEY)。
  • 客户端common/isms_client.pysearch_projects/get_number/get_sms/poll_sms/release_number/get_user_info)。
  • 补货方法AccountPool):
    • count_healthy():统计可用号数。
    • register_one_via_isms(isms, project, proxy_url, ...):单号全自动注册(接码取号→得卡 sms_send→接码 poll_sms 收码→得卡 sms_login 入库→release_number)。
    • auto_replenish(target_min, target_max, free_proxy_urls, keyword, ascription, api_key):巡检补货,healthy < target_min 时补到 target_max;每号随机停顿 30~90s 错峰防连坐。

补货流程

search_projects("得卡") → 选项目
get_number(项目, ascription=2实体卡) → 手机号 + orderId
[得卡] sms_send(手机号) → 得卡发验证码
poll_sms(orderId) 轮询(每5s,≤180s) → 收到验证码
[得卡] sms_login(手机号, 验证码, proxy_url) → 入库 healthy
release_number(orderId)

配置(2026/09/09)POOL_TARGET_SIZE=20(池子目标 20 个账号);ISMS_ASCRIPTION=None(卡类型不限制isms_client 会剔除 None 参数不发送,由平台按可用号分配);每号随机停顿 30~90s 错峰,避免一批新号被批量连坐识别。

API KeyISMS_API_KEY 常量写在 common/account_pool.py(主公定放代码,非 git 仓库);敏感,勿外传/勿提交公开仓库。

硬约束:自动注册能出无限号,但每号绑 1 个 IP,池子规模上限 = 买的 IP 数(20 账号≈20 个 IP,或自己独享 IP 下 1 IP : 2~3 号低密度共用)。auto_replenishfree_proxy_urls 用尽即停。

已实测确认(2026/09/09):得卡接码项目关键词 ISMS_PROJECT_KEYWORD="优豪卡"→项目「优豪卡科技」(project_id=119481);Key 有效、余额=3(补号需充值);isms_client 必带浏览器 UA(否则被爱接码 WAF 拦 403,已内置)。

待资源才能真跑:空闲专属静态 IP 列表(快代理共享版+静态型 20 IP,¥1000/月)填 free_proxy_urls。接口端点/参数码表见项目 memory isms-api-reference


10. 实测记录汇总(2026/09/09)

  • 短信登录接口签名 send/login 两样本哈希与 make_signature 完全命中。
  • 短信登录=注册端到端跑通:sms_sendsms_login(入库)→acquire_randomensure_access(续签 + refresh 正确轮换 + 回写 DB)→release
  • 判死码 10010 实测确认(refresh 失效返回)。
  • step3 端到端跑通:启用账号池后 do_request(need_auth=True) 取商家列表,code=0、10 条。
  • IP:123proxy 北美 IP 连通得卡但异地风控高危/延迟高,弃用。快代理共享版+静态型 20 个国内 IP实测得卡认(洛阳 IP 发 need_auth 请求 code=0)。
  • 自动补货全链路试点成功:接码取号 17047146344 → 得卡发码 → 接码收到验证码短信 → sms_login 注册入库 + 绑 IP。接码「优豪卡」号确实能收得卡短信。
  • 配置集中 common/settings.py;一键补号脚本 spiders/replenish_accounts.py--target/--batch);auto_replenish 带连续失败熔断(5 次)。
  • 账号池运维:测试号 19521500850 为主公自用(不进池);表 TRUNCATE 重置后 17047146344 为 id=1。

11. 上线步骤(TODO,按顺序)

  1. 买 IP:快代理共享版 1 个月(先确认固定 IP)。
  2. 绑测试号验证:把 IP 填进 deca_account_record id=1 的 proxy_url,跑几天观察得卡认不认、是否判死。
  3. 录号:验证 OK 后,提供真实号,逐个 sms_send + 收码 + sms_login 入库 + 绑各自 proxy_url(1 号 1 IP,或自己独享 IP 低密度多号 1:2~3)。
  4. 启用采集:各采集入口加 core.init_account_pool(pool, task_tag=...);小流量观察。
  5. 购买记录分片buy_record_spider 支持按商家分片 + 错相位(待办)。
  6. 清理:账号池验证 OK 后清理 token.json/token.json.lock 及 core 里基于 CWD 读 token.json 的逻辑。

12. 注意事项 / 踩坑

  • 跨目录同账号踩废 token:账号池落地前,新目录脚本只做 py_compile,不真跑真实生产账号的续期——否则会作废旧目录任务正在用的 refresh(得卡 refresh 一次性轮换)。测试号 19521500850 是独立号,用它真跑与旧目录零冲突。
  • proxy_url 必须静态独享:隧道代理每次换 IP,破坏账号↔IP 绑定,等于白搭。
  • 接码平台自动补货框架已落地(见 9.5):既定方向是全自动注册补货。风控上务必用实体卡、错峰注册;受 IP 数量硬约束。主力可先用真实号跑通,资源齐了再启用巡检补货。
  • 共享 IP 稳定性会漂移:共用者变化会改变 IP 干净度,「今天稳」不代表长期稳,需持续监控集体判死信号。