trading 新增 4 条购物车接口(POST /api/cart/{add,status,clear,remove}),
全部 Bearer 鉴权、走 SiteInteractor(Playwright + storage_state)。同步把
SiteInteractor 从 gateway URL 解耦——lifespan 总是构造与启停,container
字段 worker_site → site,加 asyncio.Lock 让 HTTP 与 worker 共用同一把锁
(同账号串行硬约束)。clear/remove 用 UI 点击 button[aria-label="削除"],
探针回报这是稳定 selector;真账号实测前先用此路径。
抽 ichiba 加购字段解析到 app/shared/purchase_contract.py(常量 +
inventory_flag_for + basket_domain_of + base_form_fields),原本 scraping
与 trading 重复实现同一段 __INITIAL_STATE__.purchase 解析。进一步发现
README 写的「purchase 块是两服务契约」实际未落地——trading 必须 Playwright
开页(httpx 被 TLS 指纹拦死),本地抽比再调 /api/item_detail 更快更新鲜。
删除 scraping 端 PurchaseInfo/PurchaseOption/PurchaseOptionValue 模型、
各站 _purchase_info 函数、tests/test_purchase.py。ItemDetailData 保留
purchase_condition / is_sold_out / purchase_unit / sku 等商品状态字段。
README「加购与下单」段重写。
328 测试全绿(含架构测试守住三方互不 import)。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
44 lines
2.2 KiB
Python
44 lines
2.2 KiB
Python
"""交易服务容器:集中管理交易侧服务实例,用于依赖注入
|
|
|
|
持有三类东西:
|
|
- 登录态会话(auth_session)——加购与下单必须用同一份 cookie,全程共享
|
|
- 站点交互器(site)——持有 Playwright BrowserContext,加购/校验/清空/删除共用。
|
|
不依赖 gateway URL:HTTP 接口与 worker 都要用它,故总是构造。
|
|
- 本地下单 worker(可选)——RAKUTEN_ORDER_GATEWAY_URL 留空时整套不构造
|
|
|
|
worker 的子组件(gateway_client / local_db / evidence_store / runner)都在
|
|
app.trading.worker 包内,与抓取/网关互不 import;worker 需要商品数据时走抓取
|
|
服务的 HTTP 接口,需要任务调度时走网关的 HTTP 接口。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from app.shared.config import Settings
|
|
from app.trading.services.auth_session import AuthSession
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class TradingContainer:
|
|
"""交易服务容器
|
|
|
|
与抓取容器最本质的差别不是字段多少,而是**这个进程有状态**:登录态、
|
|
订单、页面证据都属于某个具体账号,因此交易服务只能单实例运行
|
|
(或按账号分片),不能像抓取服务那样随意横向扩容。
|
|
|
|
site 字段始终构造(HTTP /api/cart/* 接口与 worker 都依赖它)。
|
|
worker_* 字段在 RAKUTEN_ORDER_GATEWAY_URL 留空时为 None——此时交易服务
|
|
只跑登录态与购物车接口,不起后台 worker。
|
|
"""
|
|
|
|
settings: Settings
|
|
auth_session: AuthSession
|
|
# 站点交互器:持有 Playwright + 账号 cookie,加购/校验/清空/删除共用一份。
|
|
# 不依赖 gateway URL——HTTP 接口与 worker 都要用它,故总是构造。
|
|
site: object | None = None # app.trading.worker.site_interact.SiteInteractor
|
|
# 以下四项仅在 order_gateway_url 配置时构造;否则为 None,worker 不启动
|
|
worker_client: object | None = None # app.trading.worker.client.GatewayClient
|
|
worker_local_db: object | None = None # app.trading.worker.local_db.LocalDB
|
|
worker_evidence: object | None = None # app.trading.worker.evidence.EvidenceStore
|
|
worker_runner: object | None = None # app.trading.worker.runner.WorkerRunner
|