From 729e5a0f3593bf4f11a2e384e472c0a940f1771d Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Thu, 25 Jun 2026 13:59:58 +0800 Subject: [PATCH] =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 + docs/DEPLOYMENT_WINDOWS.md | 478 +++++++++++++++++++++++++++++++++++++ 2 files changed, 482 insertions(+) create mode 100644 docs/DEPLOYMENT_WINDOWS.md diff --git a/README.md b/README.md index 3510128..6403f51 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,10 @@ XADD purchase:tasks * task_id "task_test_1001" topic "surugaya_tasks" purchase_a --- +## 🖥 Windows 裸机部署 + +如需在 Windows 物理机或 Windows 云服务器上以裸机方式部署本项目与 `../jp_surugaya`,请参考 [`docs/DEPLOYMENT_WINDOWS.md`](docs/DEPLOYMENT_WINDOWS.md)。 + ## 🐳 Docker 部署(Linux 服务器 + noVNC 远程桌面) 容器内通过 supervisord 编排 5 个进程:`Xvfb`(虚拟显示器 :99)→ `fluxbox`(窗口管理器)→ `x11vnc`(VNC server)→ `noVNC/websockify`(浏览器远程桌面)→ 业务进程。浏览器以有头模式跑在虚拟桌面上,Google Pay 模板匹配、pyautogui 鼠标操作与 FFmpeg 录屏(Linux 下自动切换为 `x11grab`)均在该桌面执行。 diff --git a/docs/DEPLOYMENT_WINDOWS.md b/docs/DEPLOYMENT_WINDOWS.md new file mode 100644 index 0000000..c44a493 --- /dev/null +++ b/docs/DEPLOYMENT_WINDOWS.md @@ -0,0 +1,478 @@ +# Windows 裸机部署指南 + +> 本文档说明如何在 Windows 裸机环境下部署以下两个互相配合的服务,不依赖 Docker 或 WSL。 +> 部署对象: +> +> - `jp_pruchase_zdh_5`:采购自动化 worker(浏览器自动化下单、定时抓取通知/订单、截图归档)。 +> - `../jp_surugaya`:骏河屋抓取 API 服务(搜索/详情/通知/订单查询,并可向 Redis 投递采购任务)。 +> +> 两个服务通过 **Redis** 共享任务队列与状态数据;Redis 由 `../jp_surugaya` 侧统一部署,本服务(采购 worker)只需配置连接信息。 + +--- + +## 1. 部署架构 + +```text +┌─────────────────────────────────────────────────────────────┐ +│ Windows 服务器 │ +│ ┌──────────────────┐ ┌──────────────────────────┐ │ +│ │ jp_surugaya │◄───────►│ Redis (Windows) │ │ +│ │ :31106 │ │ :6379 │ │ +│ └──────────────────┘ └───────────┬──────────────┘ │ +│ ▲ │ │ +│ │ HTTP API │ Redis Stream │ +│ ▼ ▼ │ +│ ┌──────────────────────────────────────────────────────┐ │ +│ │ jp_pruchase_zdh_5 │ │ +│ │ - 消费采购任务 │ │ +│ │ - 浏览器自动化(Playwright) │ │ +│ │ - 截图/录屏归档到 archives/ │ │ +│ │ - 截图查看 API :8080 │ │ +│ └──────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +- **Redis**:由 `../jp_surugaya` 侧统一部署和维护,采购 worker 通过其连接信息接入。 +- **jp_surugaya**:对外提供 HTTP API(默认 `0.0.0.0:31106`),内部通过 Redis 读写任务与抓取结果。 +- **jp_pruchase_zdh_5**:不直接对外暴露业务端口,但内置截图查看 API(默认 `0.0.0.0:8080`),建议仅本地或内网访问。 + +--- + +## 2. 环境准备 + +### 2.1 操作系统 + +- Windows 10/11 64 位,或 Windows Server 2019/2022。 +- 建议固定显示分辨率(例如 `1920x1080`),并保证登录会话处于交互式桌面环境(本地显示器或持续 RDP 会话)。 + +### 2.2 Python + +- 安装 **Python 3.12+**(推荐从 [python.org](https://www.python.org/downloads/windows/) 下载)。 +- 安装时勾选 **Add python.exe to PATH**。 +- 验证: + +```powershell +python --version +``` + +### 2.3 uv(推荐) + +两个项目均使用 `uv` 作为包管理器。安装方式: + +```powershell +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" +``` + +安装完成后重启 PowerShell,并验证: + +```powershell +uv --version +``` + +### 2.4 Redis 接入信息 + +Redis 由 `../jp_surugaya` 侧统一部署,本服务不需要单独安装 Redis。 + +部署采购 worker 前,只需确认以下信息: + +- Redis 主机地址、端口、密码、DB 编号。 +- 采购 worker 与 `../jp_surugaya` 必须访问同一个 Redis 实例。 + +若本地开发测试时需要临时 Redis,可另行准备 Windows 版 Redis 或 Memurai;生产环境建议统一使用 `../jp_surugaya` 提供的实例。 + +### 2.5 浏览器 + +两个项目都基于 Playwright。首次部署时安装 Chromium: + +```powershell +uv run playwright install chromium +``` + +> 默认使用 Playwright 自带的 Chromium。若 `accounts.yaml` / `.env` 中指定了 `browser_channel=chrome`,请额外安装 Google Chrome 并确保其在系统 PATH 中可被找到。 + +### 2.6 FFmpeg(可选) + +仅在需要开启任务级桌面录屏时安装: + +1. 从 [ffmpeg.org](https://ffmpeg.org/download.html#build-windows) 下载 Windows build。 +2. 解压后将 `bin` 目录加入系统 PATH。 +3. 验证: + +```powershell +ffmpeg -version +``` + +--- + +## 3. 目录规划示例 + +建议将两个仓库放在同一父目录下,便于统一管理: + +```text +C:\jp-deploy\ +├── jp_pruchase_zdh_5\ # 采购 worker +├── jp_surugaya\ # 抓取 API(含 Redis) +├── chrome-profile\ # 浏览器登录态持久化目录 +│ ├── acc_01\ +│ └── acc_02\ +├── archives\ # 截图/录屏归档(可选,也可放在项目内) +└── logs\ # 日志汇总(可选) +``` + +后续示例均基于以上目录。 + +--- + +## 4. 部署 jp_surugaya(抓取服务) + +### 4.1 进入项目目录 + +```powershell +cd C:\jp-deploy\jp_surugaya +``` + +### 4.2 配置环境变量 + +复制示例文件: + +```powershell +copy .env.example .env +``` + +编辑 `.env`,生产环境最小可用示例如下: + +```ini +# 服务监听 +SURUGAYA_APP_HOST=0.0.0.0 +SURUGAYA_APP_PORT=31106 +SURUGAYA_APP_ENV=prod + +# 日志 +SURUGAYA_LOG_LEVEL=INFO +SURUGAYA_LOG_TO_FILE=true +SURUGAYA_LOG_DIR=logs + +# API 鉴权(必须替换为强随机字符串) +SURUGAYA_BEARER_TOKEN=REPLACE_WITH_STRONG_RANDOM_TOKEN + +# 浏览器 +SURUGAYA_BROWSER_ENABLED=true +SURUGAYA_BROWSER_HEADLESS=false +SURUGAYA_BROWSER_CHANNEL= +SURUGAYA_BROWSER_KEEP_OPEN_ON_ERROR=false + +# 代理(建议日本 IP) +SURUGAYA_PROXY_SERVER=http://127.0.0.1:7890 +SURUGAYA_PROXY_USERNAME= +SURUGAYA_PROXY_PASSWORD= + +# Redis(与采购 worker 使用同一实例) +SURUGAYA_REDIS_HOST=127.0.0.1 +SURUGAYA_REDIS_PORT=6379 +SURUGAYA_REDIS_PASSWORD= +SURUGAYA_REDIS_DB=0 +``` + +> 注意: +> - `SURUGAYA_APP_ENV` 要与采购 worker 的 `APP_ENV` 保持一致(推荐均为 `prod`),否则 Redis key 后缀不同,会导致通知/订单数据互相看不到。 +> - 若不需要无头调试,Windows 裸机建议保持 `SURUGAYA_BROWSER_HEADLESS=false`,便于观察 Cloudflare 页面。 + +### 4.3 安装依赖与浏览器 + +```powershell +# 如果私有 PyPI 索引需要认证,先设置用户名密码 +$env:UV_INDEX_JERRYYAN_USERNAME="your_username" +$env:UV_INDEX_JERRYYAN_PASSWORD="your_password" + +uv sync +uv run playwright install chromium +``` + +### 4.4 启动服务 + +项目已提供 PowerShell 启动脚本,推荐直接使用: + +```powershell +.\start-server.ps1 +``` + +可选参数: + +- `-Port 31106`:指定端口。 +- `-HostName 0.0.0.0`:指定监听地址。 +- `-NoKillExisting`:端口占用时不自动结束旧进程。 +- `-DryRun`:仅做检查,不实际启动。 + +如果不希望使用脚本,也可以手动启动: + +```powershell +uv run python -m app.main +``` + +### 4.5 验证 + +```powershell +curl http://127.0.0.1:31106/health +``` + +测试带鉴权的搜索接口: + +```powershell +curl -H "Authorization: Bearer REPLACE_WITH_STRONG_RANDOM_TOKEN" ` + -H "Content-Type: application/json" ` + -X POST "http://127.0.0.1:31106/api/search" ` + -d '{"search_word":"cat","category":"","page":1}' +``` + +--- + +## 5. 部署 jp_pruchase_zdh_5(采购 worker) + +### 5.1 进入项目目录 + +```powershell +cd C:\jp-deploy\jp_pruchase_zdh_5 +``` + +### 5.2 配置环境变量 + +复制示例文件为生产配置: + +```powershell +copy .env.example .env.prod +``` + +编辑 `.env.prod`,生产环境最小可用示例如下: + +```ini +APP_ENV=prod +LOG_LEVEL=INFO +LOG_DIR=./logs + +# Redis(必须与 jp_surugaya 同一实例) +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD= +REDIS_DB=0 + +# 消费者标识(多 worker 部署时建议为每个实例设置唯一名称) +REDIS_CONSUMER_GROUP=purchase_group +REDIS_CONSUMER_NAME=purchase_worker_01 + +# Redis key 名称(与 jp_surugaya 共用,prod 环境不带 _dev 后缀) +# 这些 key 的默认值已由 surugaya-common 的 redis_keys 定义一致,通常无需显式覆盖 +REDIS_STREAM_KEY=jp_surugaya_purchase_task +REDIS_DELAY_ZSET_KEY=jp_surugaya_trade_delay +REDIS_NEWS_HASH_KEY=jp_surugaya_news +REDIS_TRADE_FETCH_STREAM_KEY=jp_surugaya_trade_fetch +REDIS_TRADE_FETCH_CONSUMER_GROUP=surugaya_trade_fetch_group +REDIS_TRADE_FETCH_CONSUMER_NAME=surugaya_trade_fetch_worker + +# 节点标识(用于 trade delay zset,最终 key 为 REDIS_DELAY_ZSET_KEY:NODE_ID) +NODE_ID=node_1 + +# 通知定时抓取 +NEWS_FETCH_ENABLED=true +NEWS_FETCH_INTERVAL_SECONDS=300 + +# 浏览器 +BROWSER_HEADLESS=false +BROWSER_EXECUTABLE_PATH= +BROWSER_KEEP_OPEN=false +LOGIN_PRECHECK_ENABLED=true + +# 配置与资源路径 +ACCOUNTS_CONFIG_PATH=./accounts.yaml +SCREENSHOT_DIR=./archives + +# 任务上报(按需配置回调地址与签名密钥) +CALLBACK_URL= +APPID= +APP_SECRET= + +# 通知配置(失败时发邮件) +NOTIFY_ENABLED=false +NOTIFY_CHANNELS=email +NOTIFY_ON_TASK_FAILED=true + +MAIL_ENABLED=true +MAIL_SMTP_HOST= +MAIL_SMTP_PORT=465 +MAIL_SMTP_USE_SSL=true +MAIL_SMTP_STARTTLS=false +MAIL_USERNAME= +MAIL_PASSWORD= +MAIL_FROM_ADDRESS= +MAIL_FROM_NAME=JP Purchase Bot +MAIL_TO_ADDRESSES=ops@example.com +MAIL_SUBJECT_PREFIX=[JP-Purchase] +MAIL_TIMEOUT_SECONDS=10 +``` + +> 注意: +> - Redis 实例由 `../jp_surugaya` 侧统一部署,本配置只需填写正确的连接信息。 +> - `APP_ENV=prod` 时,Stream / Hash / ZSet 的 key 默认不带 `_dev` 后缀;若 `jp_surugaya` 与采购 worker 的 prod/dev 环境不一致,会出现通知/订单数据互相看不到、任务投递后无法消费等问题。 +> - `REDIS_DELAY_ZSET_KEY` 最终使用的 key 为 `{REDIS_DELAY_ZSET_KEY}:{NODE_ID}`,因此 `NODE_ID` 必须与 `jp_surugaya` 调用 `/api/order/add_trade_monitor` 时传入的 `node_id` 保持一致。 + +### 5.3 配置账号 + +编辑项目根目录的 `accounts.yaml`。Windows 裸机部署示例: + +```yaml +sites: + surugaya: + - account_id: "acc_01" + username: "your_username@example.com" + password: "your_password" + # 使用绝对路径,建议使用正斜杠 + user_data_dir: "C:/jp-deploy/chrome-profile/acc_01" + proxy: "http://127.0.0.1:7890" + + - account_id: "acc_02" + username: "your_username2@example.com" + password: "your_password2" + user_data_dir: "C:/jp-deploy/chrome-profile/acc_02" + proxy: "http://127.0.0.1:7890" + + mercari: [] + yahoo: [] +``` + +> 提示: +> - `user_data_dir` 用于持久化浏览器登录态;首次启动前确保目录已存在。 +> - 如需清除登录态重新登录,直接删除对应目录即可。 +> - 密码若为空字符串 `""`,系统会尝试使用已有 Cookie 登录。 + +### 5.4 安装依赖与浏览器 + +```powershell +# 如果私有 PyPI 索引需要认证,先设置用户名密码 +$env:UV_INDEX_JERRYYAN_USERNAME="your_username" +$env:UV_INDEX_JERRYYAN_PASSWORD="your_password" + +uv sync +uv run playwright install chromium +``` + +### 5.5 启动 worker + +```powershell +$env:APP_ENV="prod" +uv run python -m src.main +``` + +启动后,worker 会: + +1. 加载 `.env.prod` 与 `accounts.yaml`。 +2. 预热所有已配置账号的浏览器上下文。 +3. 执行登录预检(`LOGIN_PRECHECK_ENABLED=true`)。 +4. 启动 Redis Stream 监听器、延迟任务监听器、订单抓取监听器、通知定时调度器。 +5. 启动截图查看 API(`http://0.0.0.0:8080/`)。 + +### 5.6 验证 + +1. 查看日志输出,确认无配置错误。 +2. 打开浏览器访问 `http://127.0.0.1:8080/`,应能看到截图查看器。 +3. 向 Redis Stream 投递一条测试任务: + +```powershell +redis-cli XADD jp_surugaya_purchase_task * task_id "task_test_001" topic "surugaya_tasks" purchase_account "acc_01" site_id "surugaya" record_video "0" payload "{\"item_list\":[{\"id\":\"m72275988725\",\"price_limit\":6500,\"number\":1}]}" +``` + +> 如果 Redis 设置了密码,请使用 `redis-cli -a your_password ...`。 + +--- + +## 6. 长期后台运行(可选) + +Windows 裸机环境下,可采用以下方式让服务随系统启动并保持运行: + +### 6.1 使用任务计划程序(Task Scheduler) + +1. 创建基本任务,触发器选择“当用户登录时”或“启动时”。 +2. 操作选择“启动程序”,程序路径填写 `powershell.exe`。 +3. 参数示例(采购 worker): + +```text +-WindowStyle Hidden -Command "cd C:\jp-deploy\jp_pruchase_zdh_5; $env:APP_ENV='prod'; uv run python -m src.main" +``` + +4. 在“常规”选项卡中勾选“不管用户是否登录都要运行”时,服务将运行在 Session 0,可能导致 `pyautogui`、模板匹配、录屏等依赖桌面的功能失败。因此: + +> **建议**:采购 worker 必须运行在**交互式用户会话**中(本地登录或持续 RDP 会话)。抓取 API 服务可运行在非交互式账户下。 + +### 6.2 使用 NSSM + +[NSSM](https://nssm.cc/) 可将任意程序封装为 Windows 服务。仅建议用于 `jp_surugaya`;采购 worker 因需要桌面交互,不建议使用 NSSM。 + +--- + +## 7. 升级维护 + +1. 拉取最新代码(如使用 git): + +```powershell +cd C:\jp-deploy\jp_pruchase_zdh_5 +git pull +``` + +2. 重新同步依赖: + +```powershell +uv sync +``` + +3. 重启对应 PowerShell 窗口中的进程即可。 + +> 提示:采购 worker 在 Windows 上不支持通过内置 API(`POST /api/restart`)重启,修改 `accounts.yaml` 后请手动重启进程。 + +--- + +## 8. 常见问题 + +### 8.1 `uv sync` 失败,提示私有索引 401 + +确认已设置: + +```powershell +$env:UV_INDEX_JERRYYAN_USERNAME="your_username" +$env:UV_INDEX_JERRYYAN_PASSWORD="your_password" +``` + +### 8.2 Playwright 启动浏览器失败 + +- 确认已执行 `uv run playwright install chromium`。 +- 确认已安装 [Microsoft Visual C++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe)。 +- 若指定了 `BROWSER_EXECUTABLE_PATH` 或 `SURUGAYA_BROWSER_CHANNEL=chrome`,确认 Chrome 已安装且路径正确。 + +### 8.3 模板匹配(Google Pay 确认按钮等)失败 + +- 确认当前屏幕分辨率与 `resources/images/` 下模板图的采集分辨率一致(推荐 `1920x1080`)。 +- 若分辨率不同,请在当前分辨率下重新截取模板图并替换原文件。 + +### 8.4 端口被占用 + +- `31106` 被占用:先结束旧的 `python.exe` / `uvicorn` 进程,或修改 `.env` 中的 `SURUGAYA_APP_PORT`。 +- `8080` 被占用:采购 worker 内置截图 API 默认使用 8080,若被其他程序占用,目前需修改源码中 `src/api/server.py` 的默认端口。 + +### 8.5 调用 `/api/search` 返回 403 + +检查请求头中的 `Authorization: Bearer ` 与 `.env` 中的 `SURUGAYA_BEARER_TOKEN` 是否一致。 + +### 8.6 采购 worker 收不到 jp_surugaya 投递的任务 + +检查两边 Redis 配置是否指向同一主机/端口/DB,并确认 `APP_ENV`(采购侧)与 `SURUGAYA_APP_ENV`(抓取侧)一致(例如都是 `prod`)。 + +### 8.7 账号登录态失效 + +删除该账号对应的 `user_data_dir` 目录,重启 worker 后会重新走登录流程。 + +--- + +## 9. 安全建议 + +- **不要**将 `8080` 端口直接暴露到公网;截图查看器与账号配置接口均无额外应用层鉴权。 +- `31106` 若需对外提供,请通过反向代理并加鉴权(如 Nginx / Cloudflare Access / 企业 VPN)。 +- `SURUGAYA_BEARER_TOKEN` 应使用至少 32 位的强随机字符串。 +- 敏感信息(密码、Token、SMTP 密码)只存放在 `.env` / `accounts.yaml` 中,不要提交到 Git。 +- 建议为日本站点使用稳定的日本 IP 代理,降低 Cloudflare 挑战频率。