This commit is contained in:
2026-07-27 21:29:36 +08:00
parent 18cf7ae079
commit 6247d68fb5
10 changed files with 849 additions and 128 deletions
+46
View File
@@ -91,6 +91,9 @@ class SiteInteractor:
self._browser = None
self._context = None # playwright BrowserContext
self._per_task_state = {}
# 上次 build context 时读到的 storage_state 文件 mtime。
# 用于在任务间检测 AuthSession 重登后产生的新 storage_state,触发 context 重建。
self._state_mtime: float | None = None
# ---- 生命周期 ----
@@ -109,6 +112,8 @@ class SiteInteractor:
"登录态文件不存在:site_interactor 以无 cookie 状态启动,"
"加购请求会被站点拒认"
)
else:
self._state_mtime = state_path.stat().st_mtime
self._playwright = await async_playwright().start()
self._browser = await self._playwright.chromium.launch(
@@ -127,6 +132,41 @@ class SiteInteractor:
)
logger.info("SiteInteractor 已就绪:storage_state=%s", storage_state or "(none)")
async def _refresh_context_if_stale(self) -> None:
"""检查 storage_state 文件 mtime,变化则重建 context
AuthSession.try_relogin 成功后会重写 storage_state 文件。本 context 启动时
用快照式 storage_state 创建,cookie 不会自动同步——必须关掉旧 context、
用新文件重建。在 add_to_cart / verify_cart 开头各调一次,开销可接受
(只在 mtime 变了才重建)。
"""
state_path = self._settings.auth_state_path / auth_site.profile("rakuten").state_filename
if not state_path.exists():
return
mtime = state_path.stat().st_mtime
if mtime == self._state_mtime:
return
logger.info(
"storage_state 文件变化(mtime %s%s),重建 context",
self._state_mtime, mtime,
)
if self._context is not None:
try:
await self._context.close()
except Exception:
logger.debug("关闭旧 context 失败", exc_info=True)
self._context = await self._browser.new_context(
storage_state=str(state_path),
user_agent=auth_site.RAKUTEN_USER_AGENT,
locale="ja-JP",
timezone_id="Asia/Tokyo",
viewport={"width": 390, "height": 844},
is_mobile=True,
has_touch=True,
)
self._state_mtime = mtime
async def close(self) -> None:
"""关闭 context、browser、playwright,吞掉单个 close 异常"""
for resource, name in (
@@ -171,6 +211,9 @@ class SiteInteractor:
await self._auth_session.require_logged_in("rakuten")
# 任务开始前刷新 context:AuthSession 可能刚自动重登过,storage_state 变了
await self._refresh_context_if_stale()
page = await self._context.new_page()
try:
try:
@@ -261,6 +304,9 @@ class SiteInteractor:
"""
await self._auth_session.require_logged_in("rakuten")
# 同 add_to_cart:刷新 context 以反映可能的自动重登结果
await self._refresh_context_if_stale()
per_task = self._per_task_state.get(task.task_id, {})
item_id = (task.intent or {}).get("item_id") or per_task.get("item_id")
if not item_id: