使用 lobsterai2api ↗反代网易有道 LobsterAI,并通过自动签到脚本每天获取积分,实现持续运转。建议直接将本文丢给 AI 部署。

额度说明#
获取#
- 注册赠送 300 积分,14 天有效;
- 邀请赠送 300 积分,365 天有效;
- 每日签到赠送 100 积分,30 天有效。
比率#
通过 deepseek-flash 历史消耗估算积分兑 tokens 比率如下:
| 项 | 实测结果 |
|---|---|
| 非缓存输入 | 200 积分/ 1M tokens |
| 缓存命中 | ~输入价的2%~3%(约 5 积分/ 1M tokens) |
| 输出 | ~输入价的4×(≈ 800 积分/ 1M tokens) |
注:各模型倍率不同(deepseek-flash 0.1、glm-5.3-flash 0.06、qwen3.7-max 1.33),实测 glm-5.3-flash 的单价约为 deepseek-flash 的 0.6 倍。换算时请以 /api/models/available 里的 costMultiplier 倍率为准。
准备#
- Docker 环境。
- 网易有道账号(需手机号登录)。
实施#
步骤 1:部署 Docker 服务#
创建项目目录,写入以下两个核心文件(仓库本身不含 Dockerfile,需要自己写):
1. Dockerfile
FROM golang:1.23-alpine AS build
WORKDIR /src
COPY go.mod ./
COPY cmd ./cmd
COPY internal ./internal
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/lobsterai2api ./cmd/server \
&& CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/login ./cmd/login \
&& CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/credit ./cmd/credit
FROM alpine:3.20
RUN apk add --no-cache ca-certificates tzdata && adduser -D -u 10001 -h /app app
WORKDIR /app
COPY --from=build /out/ /app/
RUN mkdir -p /app/auths /app/data && chown -R 10001:10001 /app
USER 10001
EXPOSE 8367
ENTRYPOINT ["/app/lobsterai2api", "-config", "/app/config.json"]dockerfile/out/credit 是仓库自带的查额度小工具(步骤 5 会用到),不需要可以删掉。
2. config.json(YOUR_CUSTOM_API_KEY 需自己编一个)
{
"listen": ":8367",
"api_key": "YOUR_CUSTOM_API_KEY",
"auth_dir": "/app/auths",
"state_file": "/app/data/state.json",
"cooldown": {"hard_credit": "12h", "soft_rate": "60s", "err_threshold": 3, "err_cooldown": "10m"},
"schedule": {"checkin_hours": [9, 21], "keepalive_hours": [22]},
"upstream": {"timeout_seconds": 180}
}json
schedule里的两个时刻实际只做「余额刷新 + 账号解冻」。签到靠步骤 4 的外部脚本。
3. 构建并启动容器
git clone --depth 1 https://github.com/xinxinshuhao-create/lobsterai2api.git
cd lobsterai2api
# 写入上述 Dockerfile 和 config.json 后运行:
mkdir -p auths data && chown -R 10001:10001 auths data config.json && chmod 640 config.json
docker build -t lobsterai2api:local .
docker run -d --name lobsterai2api --restart unless-stopped \
-e TZ=Asia/Shanghai \
-e LB2A_UPSTREAM_BASE=https://lobsterai-server.youdao.com \
-p 127.0.0.1:8367:8367 \
-v "$PWD/auths":/app/auths -v "$PWD/data":/app/data \
-v "$PWD/config.json":/app/config.json:ro \
lobsterai2api:localbash步骤 2:账号授权与 Token 提取#
官方登录使用的是本地回环回调,网页登录成功后,前端会跳转到 http://127.0.0.1:<随机端口>/auth/callback。
1. 获取登录链接
mkdir -p /tmp/lb2api && chown -R 10001:10001 /tmp/lb2api
docker rm -f lb2api-login 2>/dev/null
docker run -d --name lb2api-login --network host -u 10001:10001 \
-v "$PWD/auths":/app/auths -v /tmp/lb2api:/tmp \
-e LB2A_UPSTREAM_BASE=https://lobsterai-server.youdao.com \
-e LB2A_LOGIN_PORTAL=https://lobsterai.youdao.com \
--entrypoint /app/login lobsterai2api:local url
for i in $(seq 1 30); do URL=$(docker logs lb2api-login 2>&1 | grep -m1 '^https://' || true); [ -n "$URL" ] && break; sleep 0.5; done
echo "$URL"bash得到形如 https://lobsterai.youdao.com/portal#/login?source=electron&redirect_uri=...&state=... 的链接。
2. 浏览器完成登录
- Docker 跑在本地 Linux 机器:在浏览器内登录后,页面会显示「登录成功,可以关闭此窗口了」,Token 自动落盘到
auths/lobsterai-<uid>.json。 - Docker 跑在远程服务器:打开链接登录后,地址栏会变成
http://127.0.0.1:xxxxx/auth/callback?code=xxx&state=xxx并提示「无法访问此网站」,这是正常现象。把整条 URL 复制出来,在服务器上执行下面这段,把回调「打」回服务器容器里:
CB='<粘贴整条回调URL>' # 形如 http://127.0.0.1:33955/auth/callback?code=xxx&state=xxx
S=/tmp/lb2api/lb2api-login-state.json
PORT=$(python3 -c "import json;print(json.load(open('$S'))['port'])")
STATE=$(python3 -c "import json;print(json.load(open('$S'))['state'])")
CODE=$(python3 -c "import sys,urllib.parse as u;print(u.parse_qs(u.urlparse('$CB').query)['code'][0])")
curl -s -G "http://127.0.0.1:$PORT/auth/callback" --data-urlencode "code=$CODE" --data-urlencode "state=$STATE"
docker logs lb2api-login | tail -2 # 出现 "auth saved: /app/auths/lobsterai-<uid>.json" 即为成功bash同一浏览器里登录多个账号时,需要先把前一个号的登录退出,否则下一个号登录时会卡在「未获取到有道用户信息」,建议直接用无痕标签页登录。
3. 加载账号
Token 落盘为 auths/lobsterai-<uid>.json 后,重启主容器即可:
docker restart lobsterai2api
curl -s http://127.0.0.1:8367/statusbash新增账号在
/status里credits显示 0 属于正常情况,等下一次余额刷新即可。
步骤 3:接口验证#
用 curl 验证响应(需把 YOUR_CUSTOM_API_KEY 修改为之前 config.json 中填写的):
curl -s http://127.0.0.1:8367/v1/chat/completions \
-H "Authorization: Bearer YOUR_CUSTOM_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "deepseek-flash",
"messages": [{"role": "user", "content": "你好"}],
"stream": false
}'bash步骤 4:每日自动签到#
反代不自带签到功能,需另外实现。
新建 checkin.py:
#!/usr/bin/env python3
"""有道 LobsterAI 每日签到(+100 积分/号/天)。"""
import json
import pathlib
import re
import sys
import urllib.request
import uuid
BASE = "https://lobsterai-server.youdao.com"
UPDATE_API = "https://api-overmind.youdao.com/openapi/get/luna/hardware/lobsterai/prod/update"
AUTHS = pathlib.Path(__file__).resolve().parent / "auths"
CLIENT_VERSION = None
def version_key(v):
m = re.fullmatch(r"(\d+(?:\.\d+)*)(?:-[0-9A-Za-z.-]+)?", (v or "").strip())
return tuple(int(x) for x in m.group(1).split(".")) if m else None
def resolve_client_version():
try:
with urllib.request.urlopen(UPDATE_API, timeout=15) as r:
v = json.loads(r.read())["data"]["value"]["version"]
except Exception as e:
raise RuntimeError(f"官方更新接口取不到版本:{type(e).__name__}: {e}")
if not version_key(v):
raise RuntimeError(f"官方更新接口返回的版本格式异常:{v!r}")
return v
def api(method, path, tok, body=None):
req = urllib.request.Request(
BASE + path, method=method,
data=json.dumps(body).encode() if body is not None else None,
headers={
"Authorization": "Bearer " + tok,
"Accept": "application/json",
"Content-Type": "application/json",
"User-Agent": "LobsterAI/" + CLIENT_VERSION,
})
with urllib.request.urlopen(req, timeout=30) as r:
d = json.loads(r.read())
if d.get("code") != 0:
raise RuntimeError(f"code={d.get('code')} msg={d.get('message') or d.get('msg')}")
if not isinstance(d.get("data"), dict):
raise RuntimeError("data 为空(accessToken 可能已失效)")
return d["data"]
def checkin(uid, tok):
q = (f"placement=desktop_sidebar&clientVersion={CLIENT_VERSION}"
f"&containerApiVersion=2&platform=win32")
slot = api("GET", f"/api/client-activities/slot?{q}", tok)
if slot.get("slotState") != "available" or not slot.get("activity"):
return f"无可用活动(slotState={slot.get('slotState')!r})", None
code = slot["activity"]["activityCode"]
rev = slot["activity"]["configRevision"]
ctx = api("GET", f"/api/client-activities/{code}/context?configRevision={rev}", tok)
if ctx["state"].get("claimedToday") or "check_in" not in (ctx.get("actions") or []):
return "今天已签到,跳过", None
res = api("POST", f"/api/client-activities/{code}/actions/check_in", tok,
{"configRevision": rev, "idempotencyKey": str(uuid.uuid4()), "payload": {}})
result = res.get("result") or {}
gained = next((result[k] for k in ("creditsGranted", "rewardCredits", "credits")
if isinstance(result.get(k), (int, float))), None)
return "签到成功", gained
def main():
global CLIENT_VERSION
try:
CLIENT_VERSION = resolve_client_version()
except Exception as e:
print(f"解析 clientVersion 失败,本次不签到:{e}")
return 1
files = sorted(AUTHS.glob("lobsterai-*.json"))
if not files:
print(f"没找到账号文件:{AUTHS}/lobsterai-*.json")
return 1
fails = 0
for f in files:
doc = json.loads(f.read_text())
uid = doc["account"]["uid"]
try:
msg, gained = checkin(uid, doc["auth"]["accessToken"])
print(f"[{uid}] {msg}" + (f" 积分 +{gained:g}" if gained else ""))
except Exception as e:
print(f"[{uid}] 签到失败:{e}")
fails += 1
return 1 if fails else 0
if __name__ == "__main__":
sys.exit(main())python挂到定时任务(Crontab):
5 9,21 * * * cd /path/to/lobsterai2api && /usr/bin/python3 checkin.py >> data/checkin.log 2>&1bash输出结果示例:
[2026-09-14 09:05:01] 签到成功 +100 分;剩余 832.350626 分plaintext步骤 5:查询额度及到期时间(可选)#
/status 只能看到实时余额。
通过以下脚本可查询每批额度到期时间。
新建 credits.py:
#!/usr/bin/env python3
"""查所有号的额度明细与每个批次的有效期(只读 profile-summary,零成本)。"""
import datetime as dt
import json
import pathlib
import sys
import urllib.error
import urllib.request
BASE = "https://lobsterai-server.youdao.com"
AUTHS = pathlib.Path(__file__).resolve().parent / "auths"
CST = dt.timezone(dt.timedelta(hours=8)) # 接口时间戳按北京时间解释
try: # 版本与签到脚本同一个来源,不另存一份硬编码
from checkin import resolve_client_version
USER_AGENT = "LobsterAI/" + resolve_client_version()
except Exception:
USER_AGENT = "LobsterAI" # profile-summary 没有版本门槛,取不到也照样能查
def parse_exp(s):
"""expiresAt → 带时区的 datetime(接口给的是北京时间但不带 tz)。"""
s = str(s).strip().replace("Z", "+00:00")
try:
d = dt.datetime.fromisoformat(s)
except ValueError:
d = dt.datetime.strptime(s[:19], "%Y-%m-%dT%H:%M:%S")
return d.replace(tzinfo=CST) if d.tzinfo is None else d.astimezone(CST)
def summary(uid):
tok = json.loads((AUTHS / f"lobsterai-{uid}.json").read_text())["auth"]["accessToken"]
req = urllib.request.Request(BASE + "/api/user/profile-summary", headers={
"Authorization": "Bearer " + tok,
"Accept": "application/json",
"User-Agent": USER_AGENT,
})
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read())["data"]
def main():
want = sys.argv[1] if len(sys.argv) > 1 else None
files = sorted(AUTHS.glob("lobsterai-*.json"))
if want:
files = [f for f in files if f.stem == f"lobsterai-{want}"]
if not files:
print(f"没有找到账号文件:{AUTHS}/lobsterai-*.json"
+ (f"(没有 uid={want} 的号)" if want else ""))
return 1
now = dt.datetime.now(CST)
fails, rows, soon = 0, [], []
for f in files:
uid = f.stem.split("-", 1)[1]
try:
d = summary(uid)
if not isinstance(d, dict):
# 上游对失效 token 也可能回 200 + data:null
raise ValueError("响应 data 为空(通常是 accessToken 失效)")
except urllib.error.HTTPError as e:
hint = "(token 过期 → 重走一遍登录流程)" if e.code in (401, 403) else ""
print(f"❌ {uid}:HTTP {e.code} {hint}")
fails += 1
continue
except Exception as e:
print(f"❌ {uid}:{e}")
fails += 1
continue
items = sorted(d.get("creditItems") or [], key=lambda x: x["expiresAt"])
total = d.get("totalCreditsRemaining")
rows.append((uid, d.get("nickname", ""), total))
print(f"\n=== {uid} {d.get('nickname','')}:合计 {total} 分 ===")
if not items:
print(" (没有未过期批次)")
for it in items:
exp = parse_exp(it["expiresAt"])
days = (exp - now).total_seconds() / 86400
flag = " ⚠️ 7 天内到期" if days < 7 else ""
print(f" [{it['type']}] {it['label']} {it['creditsRemaining']:g} 分"
f" 到期 {exp:%Y-%m-%d %H:%M} 剩 {days:.1f} 天{flag}")
if days < 7:
soon.append((days, uid, it["creditsRemaining"]))
s = sum(i["creditsRemaining"] for i in items)
if total is not None and abs(s - total) > 0.01:
print(f" ⚠️ 批次合计 {s:g} ≠ totalCreditsRemaining {total}(口径不一致,留意)")
if rows:
print("\n" + "-" * 46)
for uid, nick, total in rows:
print(f" {uid} {nick}:{total} 分")
print(f" 合计 {sum((r[2] or 0) for r in rows):g} 分 / {len(rows)} 个号")
for days, uid, c in sorted(soon):
print(f" ⚠️ {uid} 有 {c:g} 分将在 {days:.1f} 天内到期")
print(f"\n[{dt.datetime.now(CST):%Y-%m-%d %H:%M:%S}] 结束,失败 {fails} 个")
return 1 if fails else 0
if __name__ == "__main__":
sys.exit(main())python用法:
python3 credits.py # 所有号
python3 credits.py 89410 # 只查指定 uidbash输出结果示例:
=== 89410 173****0001:合计 766.48 分 ===
[campaign] 每日登录奖励 66.48 分 到期 2026-10-10 18:25 剩 26.1 天
[campaign] 每日登录奖励 100 分 到期 2026-10-11 10:43 剩 26.8 天
[campaign] 每日登录奖励 100 分 到期 2026-10-12 17:46 剩 28.1 天
[campaign] 每日登录奖励 100 分 到期 2026-10-13 22:29 剩 29.3 天
[campaign] 每日登录奖励 100 分 到期 2026-10-14 09:05 剩 29.7 天
[invitation] 邀请奖励 300 分 到期 2027-09-10 23:45 剩 361.3 天
=== 89878 173****0002:合计 700.0 分 ===
[free] 新用户赠送 300 分 到期 2026-09-24 23:45 剩 10.3 天
...
----------------------------------------------
89410 173****0001:766.48 分
89878 173****0002:700.0 分
合计 1466.48 分 / 2 个号plaintext步骤 6:接入 API 使用#
- API 地址:
http://127.0.0.1:8367/v1 - API 密钥:
config.json中填写的YOUR_CUSTOM_API_KEY - 可用模型查询:
curl -s http://127.0.0.1:8367/v1/models -H "Authorization: Bearer YOUR_CUSTOM_API_KEY" | python3 -c "import sys,json;print(*[m['id'] for m in json.load(sys.stdin)['data']],sep='\n')"