发布日期:2026-03-30

闲鱼自动搜索项目开发复盘:从 Next.js 到飞书卡片通知

Next.jsPlaywrightSupabase飞书自动化
闲鱼自动搜索项目开发复盘:从 Next.js 到飞书卡片通知

这篇文章记录的是 xianyu-auto-search 从零到可用的完整开发复盘。项目的目标很直接:用 Next.js 16 + Playwright 做一个可配置的闲鱼监控工具,把关键词、价格、发布时间、通知方式这些能力放到网页里统一管理,最后把新商品稳定推送到飞书。

项目背景与目标

一开始我并不是想做一个“爬虫脚本”,而是想做一个可以长期使用的工具。脚本型方案的问题很明显:配置散、调试难、执行不稳定、结果不可追踪。所以这个项目从第一天起就把“可视化配置、可持续运行、可定位问题”放在比“先跑通”更靠前的位置。

最终希望实现的链路是:网页配置监控任务,服务端定时扫描,Playwright 在真实页面里完成筛选,Supabase 保存配置和去重记录,飞书接收分批通知,形成一条闭环。

技术栈与架构

项目采用 Next.js 16 App Router、React 19、TypeScript 5,UI 用 shadcn/ui + Tailwind CSS 4,数据层用 Supabase,定时任务用 node-cron。它不是标准的纯前后端分离结构,而是把页面、API、定时器、抓取逻辑放在同一个应用里,便于调试和部署。

整体结构可以理解成四层:前端配置页负责创建和编辑任务,API 负责手动触发和配置读写,自定义 server.ts 负责把 Next.js 和监控调度器一起拉起来,Playwright 与飞书则承担执行和通知。

关键开发过程与问题定位

最先遇到的是开发服务锁文件问题。Windows 下如果子进程没有完全退出,.next/dev/lock 会残留,下一次启动就会卡住。后来我把 scripts/dev.mjs 改成了带子进程树清理的启动方式,避免开发环境反复被锁住。

第二个问题出在数据层。Supabase 新建项目后表不会自动存在,所以我根据 Drizzle schema 手工整理了初始化 SQL,先把 monitor_configssent_productshealth_check 建出来,再补齐浏览器调试相关字段,保证前端配置页能直接保存。

第三个问题最有代表性:刚开始我把 Playwright 当成“无头浏览器脚本”来写,结果浏览器看似登录了,实际上下文并没有继承本机登录态。后来我把浏览器参数、可执行文件、用户目录和无头模式都做成可配置项,还把调试截图和 HTML 落到 .next/debug/xianyu/,这样问题基本都能回看。

重要实现点

Supabase 主要承担两件事:存监控配置,存已发送商品。这样去重逻辑就不必依赖内存状态,服务重启后也不会丢历史。

Next.js 自定义 dev server 是这个项目很关键的一步。src/server.ts 启动后不仅提供页面和 API,还会顺手启动监控调度器,这样调试“配置-触发-推送”链路时非常方便。

Playwright 和闲鱼筛选 的重点不是“打开页面”,而是“真的在页面里点筛选”。我先尝试通过 URL 组合参数,后来发现闲鱼的筛选更依赖页面交互,所以改成了在真实页面中点击“新发布”“价格”“个人闲置”等控件,再提取筛选后的商品卡片。

飞书通知 也经历了几轮修正。最早只是发送普通 JSON,后来发现飞书虽然返回 200,但并不代表业务成功。于是我补了响应体和业务码检查,再把通知改成 interactive 卡片,并按批次发送,避免单条消息过长。

踩坑与修复

这个项目里最典型的坑有三个。第一是浏览器登录态误判:看上去像是登录了,实际上下文没有继承,所以筛选按钮和结果页都不可靠。第二是价格过滤误差:像 2.88万 这样的值如果被错误当成 2.88 元,就会把本来正确的结果过滤掉,所以后来我直接取消了本地二次价格过滤,把判断交给闲鱼页面本身。第三是通知展示问题:飞书返回成功不代表内容完整送达,必须看响应体和业务码,同时控制单批商品数量。

这些问题的共同点是:表面症状都像“结果不对”,但真正的根因分别在浏览器上下文、数值解析和消息协议上。调试时如果只看最终结果,很容易走偏;把调试截图、HTML、请求响应和业务日志都留住,排查效率会高很多。

最终效果与后续方向

现在这套流程已经比较完整:网页能配置监控任务,服务端能定时扫,Playwright 能在真实页面里完成筛选,Supabase 负责持久化,飞书能把新商品按卡片批量推送出去。它已经不是一个单纯的爬虫脚本,而是一个可配置、可调试、可持续运行的监控系统。

后续我还想继续优化三件事:把飞书卡片做得更像真正的通知面板;把浏览器调试参数做成前端可视化配置;再把日志、最近一次截图和最近一次推送结果也展示到页面里。这样一来,这个系统就不仅能跑,还能更容易被维护和复用。