交易服务收敛为仅 rakuten:移除 rakuma 登录态与下单入口
trading 不再管理 ラクマ 的购物车购买、支付与订单监控。删除 auth_site / auth_session / login_runner / models.AuthSite 中的 rakuma 分支与常量、 account.yaml.example 的 rakuma 段,并清理相关测试。scraping 侧的 ラクマ 抓取 API(/api/rakuma/*)保留不动。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,12 +4,15 @@
|
||||
而是分进程运行,原因:
|
||||
|
||||
- 抓取是**匿名**的,cookie 只用来过 Akamai 限速,丢了重新预热即可,无状态可言。
|
||||
- 加购下单必须**带账号**,cookie 一旦失效需要重登——乐天与 ラクマ 登录都有
|
||||
reCAPTCHA 与设备验证,全自动不可靠。本服务支持「失效时自动重登 + 撞验证码弹
|
||||
有头浏览器让人工接管」的降级路径(依赖 account.yaml 与 relogin_enabled)。
|
||||
- 加购下单必须**带账号**,cookie 一旦失效需要重登——乐天登录有 reCAPTCHA 与设备
|
||||
验证,全自动不可靠。本服务支持「失效时自动重登 + 撞验证码弹有头浏览器让人工接管」
|
||||
的降级路径(依赖 account.yaml 与 relogin_enabled)。
|
||||
- 这份登录态在整个系统里只能有一份。跟抓取同进程的话,抓取一扩容就会复制出 N 份
|
||||
登录态与 N 个订单轮询,同一个账号被并发操作。
|
||||
|
||||
交易服务只管理乐天市场的购物车购买、支付与订单监控;ラクマ 抓取仍在抓取服务里
|
||||
提供,但不进入交易链路。本模块只持有 rakuten 一个站点的登录态。
|
||||
|
||||
登录态来源是 Playwright 的 storage_state:
|
||||
- 首次登录由 scripts/login.py 完成;
|
||||
- 运行时失效且 relogin_enabled=true 时,本模块自动触发 login_runner.login_one()
|
||||
@@ -75,7 +78,7 @@ class _SiteAuth:
|
||||
|
||||
|
||||
class AuthSession:
|
||||
"""持有两站登录态的会话
|
||||
"""持有登录态的会话
|
||||
|
||||
职责边界:只负责「有没有登录态、cookie 是什么、还有效吗」,
|
||||
具体加购/下单的业务请求由各自的 client 组装后借这里的 HTTP 客户端发出。
|
||||
@@ -90,7 +93,7 @@ class AuthSession:
|
||||
# ---- 生命周期 ----
|
||||
|
||||
async def start(self) -> None:
|
||||
"""为两站创建带登录 cookie 的 HTTP 客户端
|
||||
"""为站点创建带登录 cookie 的 HTTP 客户端
|
||||
|
||||
登录态文件不存在时同样创建客户端(只是没有 cookie),这样 /health 与
|
||||
/api/auth/status 能如实回报「未登录」,而不是整个服务起不来。
|
||||
@@ -175,10 +178,9 @@ class AuthSession:
|
||||
auth = self._require_site(site)
|
||||
async with auth.lock:
|
||||
try:
|
||||
if site == "rakuten":
|
||||
logged_in, detail = await self._check_rakuten(auth)
|
||||
else:
|
||||
logged_in, detail = await self._check_rakuma(auth)
|
||||
if site != "rakuten":
|
||||
raise ValueError(f"未知站点:{site}")
|
||||
logged_in, detail = await self._check_rakuten(auth)
|
||||
except httpx.HTTPError as exc:
|
||||
raise UpstreamRequestError(
|
||||
f"登录态探测请求失败:site={site} err={type(exc).__name__}: {exc}"
|
||||
@@ -201,17 +203,6 @@ class AuthSession:
|
||||
return False, "购物车页显示未登录"
|
||||
return True, "购物车页未出现未登录标记"
|
||||
|
||||
async def _check_rakuma(self, auth: _SiteAuth) -> tuple[bool, str]:
|
||||
"""/mypage 被重定向到 /users/sign_in 即未登录"""
|
||||
response = await auth.client.get(auth_site.PROFILES["rakuma"].probe_url)
|
||||
if response.status_code >= 400:
|
||||
return False, f"mypage 返回 status {response.status_code}"
|
||||
if not auth_site.is_logged_in(
|
||||
"rakuma", final_url=str(response.url), body=response.text
|
||||
):
|
||||
return False, "mypage 被重定向至登录页"
|
||||
return True, "mypage 正常返回"
|
||||
|
||||
async def require_logged_in(self, site: str) -> None:
|
||||
"""确保某站处于登录态,否则抛错
|
||||
|
||||
@@ -338,7 +329,7 @@ class AuthSession:
|
||||
)
|
||||
|
||||
def status_all(self) -> dict[str, dict[str, Any]]:
|
||||
"""两站登录态快照,供健康检查展示"""
|
||||
"""登录态快照,供健康检查展示"""
|
||||
return {name: self.status(name).to_dict() for name in self._sites}
|
||||
|
||||
def _require_site(self, site: str) -> _SiteAuth:
|
||||
|
||||
Reference in New Issue
Block a user