版本更新见 CHANGELOG,正式版本与镜像说明见 GitHub Releases。
一个面向中文二手市场的本地开源工具:按关键词和价格区间监控闲鱼商品,使用 LLM 进行需求匹配、品相分析和批量性价比判断,并通过多种通知渠道推送结果。
项目以 Python + FastAPI + SQLite + Playwright 为核心,不需要 Node.js/npm。Cookie、任务和分析结果默认保存在部署机器的本地数据库中。
本项目仅供个人学习和研究使用。请遵守闲鱼及相关平台的服务条款,控制访问频率并自行承担账号使用风险。
- 关键词、价格区间、排除词和品相要求监控
- 需求匹配、图片品相分析、批量性价比判断
- 降价重评估和重复通知抑制
- 商品与卖家信息、风险提示、价格变化和通知历史
- Server酱、企业微信机器人、飞书机器人、Gotify 等通知渠道
- Web 设置页、任务队列、运行日志和 SQLite 持久化
- 可选 Jev 类型化判断层:逐件评估、置信度裁决和低置信度回落
- Docker 镜像、noVNC 登录模式和 GitHub Actions CI
| 方式 | Windows | macOS | Linux / NAS | 推荐场景 |
|---|---|---|---|---|
| Docker Compose | 支持 Docker Desktop | 支持 Docker Desktop | 支持 Docker Engine + Compose | 最可复现的部署方式 |
| uv 本地运行 | 支持 | 支持 | 支持 | 开发、调试、需要本机浏览器登录 |
| Conda 本地运行 | 支持 | 理论上支持 | 理论上支持 | 已经使用 Conda 的环境 |
Docker 是推荐的通用部署方式:应用、Python 依赖、Chromium 和 noVNC 都封装在镜像中,Windows、macOS、Linux 和 NAS 使用同一套 Compose 配置。
git clone https://github.com/Comui520/second-eye.git
cd second-eye
cp .env.example .envWindows PowerShell 可以使用:
Copy-Item .env.example .env编辑 .env,至少配置一个 OpenAI 兼容的文本模型。也可以先保持空配置,启动后在 Web 设置页填写。
docker compose up -d --build打开:
http://127.0.0.1:18000
查看日志和停止服务:
docker compose logs -f second-eye
docker compose down首次构建会下载 Python 依赖、Chromium、Debian 系统包和 noVNC 组件,耗时取决于网络;后续构建会复用 Docker 缓存。
Docker 内的 Chromium 不会弹出到宿主机桌面,需要通过 noVNC 网页完成一次登录。默认 noVNC 关闭,避免把远程桌面长期暴露出去。
Linux/macOS/NAS 可以使用仓库提供的跨平台辅助脚本:
./scripts/start-docker.sh --login脚本会生成 data/.novnc-password,启动容器并提示访问地址。默认访问(端口可用 NOVNC_PORT 修改):
http://127.0.0.1:16080/vnc.html
完成登录后,关闭 noVNC 并保持应用运行:
./scripts/start-docker.shWindows Docker Desktop 可以直接使用 Compose 完成相同操作:
New-Item -ItemType Directory -Force data | Out-Null
Set-Content -Path data/.novnc-password -Value "请替换为至少 8 位密码" -NoNewline
$env:ENABLE_NOVNC = "1"
docker compose up -d --build
Start-Process http://127.0.0.1:16080/vnc.html登录完成后执行:
$env:ENABLE_NOVNC = "0"
docker compose up -dnoVNC 只建议在登录期间开启,不要直接暴露到公网。应用本身没有内置用户认证;如果需要局域网或公网访问,请在反向代理、VPN 或访问控制层增加认证。
在 NAS 或 Linux 主机上,将 .env 中的 BIND_ADDRESS 设置为主机的局域网地址,例如:
BIND_ADDRESS=192.168.1.20然后启动:
./scripts/start-docker.sh访问:
http://192.168.1.20:18000
需要重新登录时临时执行 ./scripts/start-docker.sh --login,完成登录后再次执行不带 --login 的命令关闭 noVNC。
不要把 BIND_ADDRESS 设置为 0.0.0.0 后直接映射到公网。默认应用和 noVNC 都没有公网安全防护。
正式版本会由 GitHub Actions 构建并推送到 GHCR。当前版本示例:
docker pull ghcr.io/comui520/second-eye:0.1.0如果希望 Compose 使用预构建镜像,可以在启动前设置镜像变量:
SECOND_EYE_IMAGE=ghcr.io/comui520/second-eye:0.1.0 docker compose pull second-eye
SECOND_EYE_IMAGE=ghcr.io/comui520/second-eye:0.1.0 docker compose up -d --no-buildPowerShell:
$env:SECOND_EYE_IMAGE = "ghcr.io/comui520/second-eye:0.1.0"
docker compose pull second-eye
docker compose up -d --no-build如果 GHCR 包是私有的,先执行 docker login ghcr.io。镜像标签使用不带 v 的版本号,例如 Git Tag v0.1.0 对应镜像标签 0.1.0。
本地运行适合开发和调试,也可以直接使用宿主机浏览器完成登录。需要 Python 3.11 或更高版本,以及 uv。
uv sync --extra dev
uv run python -m playwright install chromium
uv run python -m goodprice访问:
http://127.0.0.1:8000
测试:
uv run pytest -q如果系统尚未安装 uv,可以按 uv 官方文档安装;本仓库不静默安装系统级运行时。Windows、macOS、Linux 的命令行用法基本一致,但不同系统的浏览器、权限和代理配置可能不同。
已有 Miniconda/Anaconda 的用户可以使用:
conda env create -f environment.yml
conda activate good-price
python -m playwright install chromium
python -m goodprice已有环境需要同步依赖时:
conda activate good-price
python -m pip install -e ".[dev]"
python -m playwright install chromium
python -m goodpriceConda 不是运行本项目的必需条件;新用户优先选择 Docker 或 uv。
监控任务可在详情页填写目标型号/容量(例如 iPhone 15 / 256GB)。
商品页面标价保留为原始观察,不代表目标规格的实际售价;仅明确规格价格才用于预算与性价比判断。
价格私聊、区间价、信息冲突或详情提取失败的商品保留为待确认,不以占位价推荐。
“待询价提醒”需在任务中主动开启,默认不增加外部通知。
商品详情可单独确认/撤销人工报价,默认有效期 7 天;人工报价优先,但证据变化需复核, 过期证据不继续作为推荐依据。人工报价与页面价的来源切换不当作降价。 设置最低品相分后,未核验的图片或多规格共享样品不会绕过门槛。
当前支持可明确识别的商品范围 DOM 数据与 Schema.org Product/Offer,尚未取得真实多规格页面样本来验证所有闲鱼控件, 不能识别时显示待核验而不是猜测。v0.2.0已接入分阶段调度,并完成合成数据的Windows/Linux容器回归;真实平台组件兼容性仍有上述限制。
设置页的“媒体证据与用量”可配置保留数量、每次原图/帧配额、总输入上限、超时、缓存和解码线程。 视频默认关闭;新安装默认一次最多8张,混合媒体先分配4张原图+4帧,单一媒体可借用余量。 旧数据库默认保持4张上限;提高预算需明确确认费用、延迟、内存、存储和提供商限制,硬件建议不会提高图片数。 模型上限未知时按8张处理,只有确认提供商支持后才可提高(最高16);不自动拆成多个收费请求。
只处理详情主媒体的直接HTTP(S)资源。blob、HLS/DASH、受保护流及未知页面结构会明确跳过, 不保证所有闲鱼页面的视频组件都能识别。视频仅采样起/中/末画面,不验证音频、整段动作或动态故障。 没有明确规格关联的图片/帧是共享证据,不能据此确认某一SKU的实物品相;任务设置最低品相分时仍需有效评分。
Docker镜像内置FFmpeg/ffprobe。本地uv/Conda运行须自行安装FFmpeg并加入PATH;缺工具时视频不可分析,应用和图片功能仍可用。 视频默认最大100MiB、180秒,下载60秒、解码30秒,缓存1GiB/7天;处理中的视频和临时输出同样计入磁盘预算。 缓存被清理后保留证据摘要与时间位置,页面显示文件不可用;媒体文件通过内部编号访问,不公开签名下载地址或本地路径。 相同内容的签名URL变化不会单独触发重复视觉收费,内容/需求/模型/选图设置变化才使分析缓存失效。
列表的任务、状态、价格状态、排序、已加载范围会带入详情及操作返回链接。加载更多不再反复请求同一页,
页面返回与原生后退可恢复列表位置;选择商品或操作表单时不自动替换正在使用的列表。
设置分为账号、模型、通知、媒体与资源,单独保存互不覆盖,凭据留空保持原值,清除需明确确认。
页面使用随包提供的 HTMX 和预编译样式,保留现有简洁界面,普通启动不需要连接 CDN 或安装 Node.js。
维护者修改样式类后可按 goodprice/web/static/THIRD_PARTY.md 重建 CSS。
设备建议只在本机检测 CPU、内存及容器限额,不上传机器标识或自动提高配置;低占用/均衡仅设置工作并发, 不会增加视觉输入、开启视频或提高访问频率。设置页显示保存配置与内存保护后的实际并发;内存不足时暂缓派发,恢复后继续。
应用使用单进程协调器,把搜索、详情、解析、媒体、模型、聚合拆成持久化步骤。默认允许两个任务分阶段推进, 抓取、媒体、模型工作并发各1;慢模型期间可继续抓取另一任务。取消原有整任务结束后的固定300秒等待, 保留同账号单页面导航和默认10秒平台间隔。普通启动不需要Redis、Celery或Node.js。
默认模型上限10次HTTP请求/分钟,每轮最多30个详情、60次模型尝试和15分钟墙钟时间;重试也占配额, 429的Retry-After会延后请求。超出预算或工作容量的候选保留游标,下轮继续;暂停、删除或修改任务后拒绝旧结果。 降低并发时先排空正在执行的步骤。浏览器在所属线程内复用,任务间使用独立上下文;同一数据目录只运行一个应用进程。
每个规格按自己的确价与证据独立评分,再在当前有效、已完成的候选中比较。内容、提示词、需求或模型配置变化使缓存失效; 批次成员变化不重新请求已缓存的独立评分。每次视觉输入仍遵守媒体设置,不通过增加图片或自动拆分请求来加速。 本轮分析期间仅价格过期、其他已采集内容未变时,可刷新价格并复用已采集媒体;这不表示媒体被重新下载或核验。
通知按渠道独立持久化,发送前重新检查规格价格和任务条件。已成功渠道不自动重发;进程中断或超时可能显示“结果未知”, 需自行核验后确认重试,可能重复。删除尚未发送的通知会取消其投递,正在发送的通知无法撤回。
持久化和恢复会增加SQLite读写开销,纯本地无网络工作不一定比串行实现快。离线对照可运行
uv run --locked python scripts/benchmark_stages.py --rounds 3 --output output/benchmark,
报告相同30件合成商品的覆盖、冷/热模型调用、SQL、耗时和Python资源;压缩逻辑时钟排除真实导航等待,不能用作真实平台提速比例。
本次升级的验证范围和已知开销见 升级验证记录。
应用现使用无导入副作用的工厂;自定义 ASGI 部署请使用 uvicorn goodprice.main:create_app --factory,
原有 python -m goodprice 启动方式不变。升级旧库前先停止服务并备份数据库,回退使用旧镜像与备份库成对恢复。
配置文件:
.env.example 配置模板
.env 本地配置,不要提交
主要配置项:
| 配置项 | 作用 |
|---|---|
| XIANYU_COOKIE | 闲鱼登录 Cookie;也可以在设置页使用一键登录 |
| LLM_BASE_URL / LLM_API_KEY / LLM_MODEL | OpenAI 兼容文本模型 |
| VISION_BASE_URL / VISION_API_KEY / VISION_MODEL | 图片品相分析模型;不配置时跳过品相分析 |
| SERVERCHAN_SENDKEY | Server酱通知 |
| WECOM_WEBHOOK | 企业微信群机器人 |
| FEISHU_WEBHOOK / FEISHU_SECRET | 飞书机器人及可选签名密钥 |
| GOTIFY_URL / GOTIFY_TOKEN | Gotify 通知 |
| JEV_ENABLED | 启用实验性的 Jev 判断层 |
| JEV_BACKEND / JEV_API_KEY | Jev 后端和可选官方服务密钥 |
| PROXY | Docker 构建及运行时使用的 HTTP 代理 |
| BIND_ADDRESS | Docker 端口绑定地址,默认 127.0.0.1 |
| DEFAULT_CRAWL_INTERVAL_MINUTES | 默认抓取间隔 |
| DEFAULT_CRAWL_JITTER_MINUTES | 请求随机抖动 |
Web 设置页中的配置会保存到数据库,并覆盖 .env 中的默认值。不要把 .env、Cookie、API Key 或 data/ 提交到仓库。
Docker 和本地运行都会在项目的 data/ 目录中保存 SQLite 数据库、Cookie、日志和 noVNC 密码文件。建议:
- 定期备份 data/goodprice.db;
- 不要把 data/ 目录上传到公共仓库;
- 不要把 noVNC 端口暴露到公网;
- 迁移到 NAS 时同时迁移数据库和配置,并检查文件权限。
- main:日常开发和合并 Pull Request;
- release:稳定版本准备和验证;
- vX.Y.Z:正式 Git Tag 和 GitHub Release。
推送版本 Tag 后,GitHub Actions 会运行测试、构建 Docker 镜像并推送到 GHCR:
git switch release
git pull --ff-only origin release
git tag -a v0.2.1 -m "Release v0.2.1"
git push origin v0.2.1普通 PR 和 main/release 推送会执行测试和 Docker 构建校验,但不会覆盖正式镜像。
上面的版本号为下一次发版示例;发版前同步 pyproject.toml/锁文件并更新 CHANGELOG,通过检查后推送新Tag。
GitHub Release的版本说明使用CHANGELOG对应条目,待该Tag的镜像发布成功后再公开版本。
使用 uv:
uv sync --extra dev
uv run pytest -q使用 Conda:
conda activate good-price
python -m pytest -qDocker 构建校验:
docker compose config --quiet
docker compose build second-eyegoodprice/crawler/ 闲鱼适配器、Playwright 登录与解析
goodprice/analysis/ LLM、视觉分析和 Jev 判断层
goodprice/notify/ 通知渠道
goodprice/services/ 设置、任务、抓取流水线和队列
goodprice/web/ Web 路由和模板
tests/ 自动化测试
scripts/start-docker.sh Linux/macOS/NAS 的 Docker 辅助脚本
.github/workflows/ CI 与 GHCR 发版流程
- 本工具不保存第三方平台账号密码,只保存用户主动提供或登录产生的 Cookie。
- 请遵守目标平台服务条款,合理控制请求频率。
- 因使用本工具导致的账号限制、数据丢失或其他问题由使用者自行承担。
- 更多二手平台适配器
- 收藏链接盯降价 / 下架
- 更丰富的价格走势图表
- 通知图片和图文消息
- 商品视频解析