diff --git a/README.md b/README.md index 94bd364..166d5e6 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ Excel 行数据 cookies 保存到 `session.json`(与 exe 同目录)。登录成功后自动初始化 token bridge 和搜索 API,供后续产品/客户搜索使用。 +`HFZrs6pXKulzS` 为可选 cookie:导出数据中存在时导入,不存在时不影响必需 cookie 检查。运行期间若服务器通过 `Set-Cookie` 返回该 cookie,会自动接收,并在保存会话时保留。 + ### 2. 选择产品/客户 登录后,在"固定值设置"区域的产品和客户输入框中输入关键词,自动触发搜索并弹出下拉选择框。选中后自动获取产品详情和客户详情并缓存,缓存有效期为一个 batch(处理完一批 Excel 数据后自动清空)。 diff --git a/login_helper.py b/login_helper.py index e8583ac..de01648 100644 --- a/login_helper.py +++ b/login_helper.py @@ -1,7 +1,7 @@ """登录助手 — 解析浏览器导出的 cookies JSON,保存为 session.json。 Cookie 白名单基于 HAR 抓包分析: - - pickup-web 所有业务 API 统一使用 9 个 cookie(见 _REQUIRED_COOKIE_NAMES) + - 必需 cookie 见 REQUIRED_COOKIE_NAMES,可选 cookie 见 OPTIONAL_COOKIE_NAMES - JSESSIONID 仅 portal 主页面需要(加载 pickup 页面时作为 Referer) - enable_HFZrs6pXKulz 仅 portal UI 配置,pickup-web 不需要 """ @@ -13,8 +13,7 @@ import os import sys # 基于 portal-to-pickup-full-flow.har 分析得出的必需 cookie -# pickup-web (/pickup-web/a/*) 所有业务 API 请求都携带这 10 个 cookie -# 缺失任何一个都会导致请求失败 +# 导入及会话检查要求以下 9 个 cookie 齐全 REQUIRED_COOKIE_NAMES: set[str] = { # 会话认证(核心 — 缺失则 401/重定向到登录页) "jdpt.session.id", @@ -25,17 +24,19 @@ REQUIRED_COOKIE_NAMES: set[str] = { "COUNTY_GRAYLEVEL", "ORG_GRAYLEVEL", # $_ts 安全框架 token(缺失则 c93l5Fya 校验失败,接口拒绝服务) - "HFZrs6pXKulzS", # 会话级 token,固定不变 "HFZrs6pXKulzO", # 组织级 token,固定不变 "HFZrs6pXKulzP", # 请求级动态 token,服务端 Set-Cookie 持续更新 # portal 主页面会话(缺失则无法加载 pickup 页面,fetch_page_resources 失败) "JSESSIONID", } +OPTIONAL_COOKIE_NAMES: set[str] = {"HFZrs6pXKulzS"} +ALLOWED_COOKIE_NAMES: set[str] = REQUIRED_COOKIE_NAMES | OPTIONAL_COOKIE_NAMES -def _is_cookie_required(name: str) -> bool: - """判断 cookie 是否为 pickup 流程所必需。""" - return name in REQUIRED_COOKIE_NAMES + +def _is_cookie_allowed(name: str) -> bool: + """判断 cookie 是否在导入和保存的白名单中。""" + return name in ALLOWED_COOKIE_NAMES def get_session_path() -> str: @@ -47,16 +48,16 @@ def get_session_path() -> str: def parse_json_and_save(json_text: str) -> int: - """解析浏览器导出的 cookies JSON 数组,过滤并保存必需 cookie。 + """解析浏览器导出的 cookies JSON 数组,过滤并保存白名单 cookie。 - 只保存 _REQUIRED_COOKIE_NAMES 白名单中的 cookie(基于 HAR 分析)。 + 只保存 ALLOWED_COOKIE_NAMES 中的 cookie,仅检查 REQUIRED_COOKIE_NAMES 是否齐全。 返回保存的 cookie 数量。 """ raw = json.loads(json_text) if not isinstance(raw, list): raise ValueError("JSON 必须是数组格式") - # 过滤目标域名 + 必需 cookie 名称 + # 过滤目标域名 + 白名单 cookie 名称 target = "10.4.188.1" cookies = [] seen = set() @@ -69,7 +70,7 @@ def parse_json_and_save(json_text: str) -> int: path = c.get("path", "/") if not name: continue - if not _is_cookie_required(name): + if not _is_cookie_allowed(name): skipped.append(name) continue key = (name, domain, path) @@ -83,7 +84,7 @@ def parse_json_and_save(json_text: str) -> int: "path": path, }) - # 检查必需 cookie 是否齐全(全部 10 个缺一不可) + # 检查必需 cookie 是否齐全(全部 9 个缺一不可) found_names = {c["name"] for c in cookies} missing = REQUIRED_COOKIE_NAMES - found_names if missing: diff --git a/pickup_api.py b/pickup_api.py index 7117745..9b5dbe4 100644 --- a/pickup_api.py +++ b/pickup_api.py @@ -194,22 +194,22 @@ class PickupSession: return False def save_session(self, session_path: str): - """保存 cookies 到文件(仅保存必需 cookie,基于 HAR 分析的白名单)。 + """保存 cookies 到文件(保存白名单中的必需及可选 cookie)。 requests.Session 会自动合并服务端 Set-Cookie 响应头, 可能累积非必需 cookie。保存时只保留白名单中的 cookie。 """ - from login_helper import REQUIRED_COOKIE_NAMES + from login_helper import ALLOWED_COOKIE_NAMES all_cookies = [ {"name": c.name, "value": c.value, "domain": c.domain, "path": c.path} for c in self._http.cookies ] - required = [c for c in all_cookies if c["name"] in REQUIRED_COOKIE_NAMES] - skipped = len(all_cookies) - len(required) + saved_cookies = [c for c in all_cookies if c["name"] in ALLOWED_COOKIE_NAMES] + skipped = len(all_cookies) - len(saved_cookies) data = { - "cookies": required, + "cookies": saved_cookies, "total_in_session": len(all_cookies), - "saved": len(required), + "saved": len(saved_cookies), "skipped": skipped, } with open(session_path, "w") as f: