front/xhs-agent-desktop/engine/xhs_bridge/browser_profile.py
zzh 5a26ae0048 feat: 小红书模块迁移、登录重构与 xhs-agent-desktop 桌面 Agent
- 新增小红书前端模块(启动服务、内容分析、爆款创作、发布记录、技能卡片、拟人设置、AI 助手)

- 新增 xhs-agent-desktop 独立桌面 Agent,对接 OMS 任务调度

- 登录页重构,整合微信登录与 OMS JWT 认证

- 订单、渠道、用户中心等页面与 API 增强

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 16:13:13 +08:00

108 lines
3.4 KiB
Python

from __future__ import annotations
import random
from typing import Any, Literal
ProfileName = Literal["mobile", "desktop"]
_MOBILE_UAS: tuple[str, ...] = (
(
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 "
"(KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1"
),
(
"Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36"
),
)
_DESKTOP_UAS: tuple[str, ...] = (
(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
),
(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
),
)
_XHS_ORIGIN = "https://www.xiaohongshu.com"
_XHS_REFERER = "https://www.xiaohongshu.com/"
def pick_random_profile() -> ProfileName:
return random.choice(("mobile", "desktop"))
def pick_user_agent(profile: ProfileName) -> str:
pool = _MOBILE_UAS if profile == "mobile" else _DESKTOP_UAS
return random.choice(pool)
def resolve_profile_for_request(_config: Any | None = None) -> ProfileName:
return pick_random_profile()
def build_browser_headers(
*,
profile: ProfileName = "mobile",
user_agent: str | None = None,
cookie_header: str | None = None,
with_cookie: bool = True,
accept: str | None = None,
extra: dict[str, str] | None = None,
) -> dict[str, str]:
"""构造接近真实浏览器的请求头(用于 CDN 图片等)。"""
ua = user_agent or pick_user_agent(profile)
if profile == "desktop":
headers: dict[str, str] = {
"User-Agent": ua,
"Accept": accept
or "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Referer": _XHS_REFERER,
"Origin": _XHS_ORIGIN,
"Connection": "keep-alive",
"sec-ch-ua-mobile": "?0",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
}
else:
platform = '"Android"' if "Android" in ua else '"iOS"'
headers = {
"User-Agent": ua,
"Accept": accept
or "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Referer": _XHS_REFERER,
"Origin": _XHS_ORIGIN,
"Connection": "keep-alive",
"sec-ch-ua-mobile": "?1",
"sec-ch-ua-platform": platform,
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
}
cookie = cookie_header
if cookie is None and with_cookie:
from xhs_bridge.config import load_config
from xhs_bridge.extension_cookies import get_cookie_header_from_extension
try:
cfg = load_config()
cookie = get_cookie_header_from_extension(cfg.skills.bridge_ws_url)
except Exception:
cookie = ""
if cookie:
headers["Cookie"] = cookie
if extra:
headers.update(extra)
return headers