mcpField
P
pricewin-hotel-deal-finder

pricewin-hotel-deal-finder

github.com/price-win生产力219.5k 次安装11 周前更新
代码仓库

关于 pricewin-hotel-deal-finder

pricewin-hotel-deal-finder 是供 Agent 使用的酒店比价技能,可比较 Booking.com、Agoda、Google Hotels 和 OpenTravel 的价格。它通过一条 Node 命令按性价比、低价和品质排序,并提供预订链接。

主要功能

  1. 01比较四个来源的价格
  2. 02按性价比、低价和品质排序
  3. 03换算为美元的每晚价格
  4. 04提供直接预订链接
  5. 05支持全球城市搜索
  6. 06本地运行且无需 API 密钥

适用场景

  1. 01比较同一家酒店在 Booking.com 和 Agoda 的价格
  2. 02查找指定日期的最低价酒店
  3. 03寻找每晚低于预算的住宿

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/price-win/pricewin-skills-hub --skill pricewin-hotel-deal-finder

安装后在 Claude Code 中输入/pricewin-hotel-deal-finder确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

install.sh
package-lock.json
package.json
SECURITY.md
bin/
browse.js
daemon.js
search.js
lib/
browser-state.js
dom-extract.js
selector-cache.js
snapshot.js

详细介绍

PriceWin 酒店优惠搜索器

只需一条命令,即可比较 Booking.com、Agoda、Google Hotels 和 OpenTravel 的实时酒店价格 — 并获取按性价比、最低价和品质排序的精选结果,以及直接预订链接。

别再打开五个 OTA 标签页来寻找真正的最低价了。告诉你的 Agent “帮我找一家东京的酒店,入住日期为 8 月 12 日至 15 日,2 位客人”,此技能就会在约 30–60 秒内(已缓存的城市)返回清晰、排序后的比价结果。

以下问题可调用此技能:

  • “<city> 在 <dates> 的最便宜酒店是什么?”
  • “这家酒店在 Booking.com 还是 Agoda 上更便宜?”
  • “比较 <city> 面向 <N> 位客人的酒店价格。”
  • “帮我找一家 <city> 每晚低于 $<X> 的酒店。”
  • “<dates> 在 <landmark> 附近,性价比最高的住宿是哪家?”

每次都会通过一条命令返回下方所示的结果 — 无需来回询问澄清信息。

一条命令即可获取:

  • 🥇 性价比最高 · 🥈 最便宜 · 🥉 品质之选 — 并排精选
  • 来自最多 4 个来源 的真实每晚价格,统一换算为 USD
  • 可点击的预订链接,直接指向每家酒店价格最低的 OTA
  • 适用于全球任何城市 — 也包括经过反机器人防护的城市(上海、杭州、曼谷……),通过隐蔽的 Patchright 守护进程访问
  • 无需 API 密钥或 MCP 服务 — 只需 node/npx

结果示例:

🏨 Tokyo • Aug 12–15 • 3 nights • 2 guests
━━━━━━━━━━━━━━━━━━━━
🥇 BEST VALUE
Shinjuku Granbell Hotel
  ✅ agoda      💰 $118/night
     booking    💰 $131/night
     → Save $13 vs Booking
🥈 CHEAPEST
APA Hotel Shinjuku
  ✅ google     💰 $94/night
📊 18 hotels | agoda, booking, google, opentravel • prices in USD

安装:

npx skills add https://github.com/Price-Win/pricewin-skills-hub --skill pricewin-hotel-deal-finder

如何使用此技能

一条命令即可完成全部操作 — 通常无需先询问澄清问题。推断参数(见下文)并运行命令:

cd {baseDir} && node bin/search.js "<city>" <checkInYYYY-MM-DD> <checkOutYYYY-MM-DD> <adults> en-us

{baseDir} 是此技能的安装目录(由运行时自动解析)。如果你的运行时不会替换它,请 cd 到包含此 SKILL.md 的文件夹(其中有 bin/search.js)。避免硬编码 ~/.hermes/... 或 ~/.openclaw/... 路径 — 不同平台上的路径各不相同。

示例:

cd {baseDir} && node bin/search.js "Hangzhou" 2026-06-10 2026-06-13 2 en-us

脚本会自动处理所有操作:启动守护进程、查询 Agoda 缓存、执行 Google + Booking 内联搜索、查询 OpenTravel API(覆盖所有城市)、发现新城市,并生成格式化的分档卡片结果。运行脚本,然后将输出发送给用户。

推断参数,而不是提问(仅当城市或日期确实有歧义时才提问):

  • **年份:**除非用户另有说明,否则使用当前日期所在的年份。如果所请求的日期今年已经过去,则假定为明年。(如不确定,可用 date +%Y-%m-%d 获取今天的日期。)
  • “10-13/6” → <year>-06-10 <year>-06-13 — 按照上面的规则填写 <year>
  • “2 位客人”/“2 个人” → 2 位成人
  • **地区设置:**传递给 OTA 的语言/地区代码(控制网站语言和地区)。默认为 en-us。价格以 USD 计(Google Hotels 请求使用 gl=us&curr=USD);其他来源则遵循你传入的地区设置。

运行一次 search.js 即可完成整个工作流 — 无需额外使用 Python、curl 或临时编写抓取脚本。


操作规则——如何获得可靠结果

规则 0——只能通过 search.js(借助终端/shell 工具)操作浏览器。此处的原生浏览器工具无法使用。 此技能依赖隐身 Patchright 守护进程。运行环境的原生工具——browser_navigate / browser_open、browser_click、browser_type / browser_fill、browser_snapshot、browser_close、任何其他 browser_*,以及委派子 Agent(delegate_task / spawn_agent)——在此任务中都会失败,因此不要使用它们:

  • 这些原生工具会启动没有隐身功能的普通 Chromium,因此 Booking.com 和 Agoda 会在几秒内检测到机器人;请求会一直挂起,直到运行环境将其终止(“Command timed out after 30/60 seconds”)。这会浪费 5 分钟以上,而且什么也得不到。search.js 启动的 Patchright 守护进程可以避开机器人检测。
  • 委派的子 Agent 会从空白历史开始,且没有技能上下文,因此会退回到使用 Python/curl 抓取,而这些请求会立刻被拦截。请在当前 Agent 中运行此技能。

唯一可行的方式:

cd {baseDir} && node bin/search.js ...

规则 1——让 search.js 负责抓取;不要自行抓取 OTA。 避免直接调用 browse.js、在浏览器中执行 goto / click / type、手动拼接 Agoda/Booking/Google URL、单独调用 OpenTravel API,或自行启动守护进程。search.js 已通过谨慎设计的流程驱动隐身守护进程,可避开机器人检测——它会为每个城市(包括上海、杭州等中国城市)自动处理 Agoda 探索。手动浏览 OTA 是最常见的失败原因:这会触发 Agoda/Booking 的反机器人机制(“detect automation”“redirect to homepage”“problem completing your search”),并导致 IP 被封锁。运行一次 search.js 并发送其输出。如果某个来源看起来“缺失”,请参阅规则 4,而不要手动获取。

规则 2——首次探索城市需要 2–4 分钟。 如果 search.js 输出中包含 "discovering" 或 "launching" 消息,请告诉用户:“首次搜索此城市——正在探索选择器,大约需要 2–4 分钟……”,然后等待结果,不要重试或中止。

规则 3——原样发送输出。 search.js 会输出可直接发送的格式化分档卡片。将输出直接复制到回复中。不要重新排版、总结或缩写。

规则 3a——保留 Markdown 超链接。 输出中的每个酒店名称都已包装为 [Hotel Name](https://booking-url...),即可点击的超链接。请保持原样:不要将 URL 拆到单独的 🔗 https://... 行,不要把 [Hotel Name](url) 替换为纯文本,OTA 名称保持小写(使用 "google",不要使用 "Google"),并保留原样的分区标题("📋 More good deals")。输出已适配 Telegram-MarkdownV2;原样发送即可让用户看到带隐藏 URL 的可点击酒店名称(界面简洁)。

规则 3b——你自行撰写的说明中也要为酒店名称添加超链接。 如果你在输出后添加建议或说明,请将提到的每个酒店名称都包装为 [Hotel Name](url),并使用脚本为该酒店打印的相同 URL,而不要使用纯文本。

规则 4——部分结果很常见,应原样发送,不要手动补全。 某个来源可能在一次运行中缺失(例如本次运行中 Agoda 被拦截,或 OpenTravel 在该城市没有库存)。这没关系——将现有来源的分档卡片发送出去;页脚(📊 N hotels | <sources> • prices in USD)会准确列出找到的内容。通过浏览器或直接 URL 获取缺失来源通常会触发反机器人机制,让情况更糟,因此请避免这样做。如果 search.js 完全报错,请用一行说明失败原因,并展示错误上方打印的任何部分输出。若需获取更多结果,唯一可靠的重试方式是再次运行相同的 search.js 命令(反机器人拦截通常只是暂时的)。


输出格式参考

search.js 会按此格式打印分档卡片 — 你可直接发送给用户:

酒店名称是指向其最便宜 OTA 的 Markdown 链接。价格行不带链接,OTA 键以小写形式显示(agoda/booking/google/opentravel)。 没有星级或区域信息行 — 脚本没有这些数据。

🏨 <city> • <d1>–<d2> • <N> nights • <adults> guests
━━━━━━━━━━━━━━━━━━━━

🥇 BEST VALUE
[<Hotel Name>](<cheapest_link>)
  ✅ agoda      💰 <price>/night
     booking    💰 <price>/night
     opentravel 💰 <price>/night
     → Save <diff> vs Booking

🥈 CHEAPEST
[<Hotel Name>](<cheapest_link>)
  ✅ google     💰 <price>/night
     agoda      💰 <price>/night

🥉 QUALITY
[<Hotel Name>](<cheapest_link>)
  ✅ booking    💰 <price>/night
     agoda      💰 <price>/night

📋 More good deals
  — Agoda —
  • [<Hotel>](<agoda_link>) — agoda: <price> | booking: <price>
  — Booking —
  • [<Hotel>](<booking_link>) — booking: <price>
  — Google —
  • [<Hotel>](<google_link>) — google: <price>
  — OpenTravel —
  • [<Hotel>](<opentravel_link>) — opentravel: <price>

💡 Tip: <best Hotel Name>
   [Book on <OTA>](<link>) — <price>/night

📊 <N> hotels | <sources with data> • prices in USD

所有价格均以 USD 显示。Agoda、Google 和 OpenTravel 会根据 IP 将货币锁定为 VND,并通过实时汇率换算;Booking 原生返回 USD。页脚仅列出实际返回数据的来源。


限制

  • 每个城市的首次搜索需要支付 Agoda 发现成本(2–4 分钟)。Google 和 Booking 会直接内联返回(无需发现);OpenTravel 是直接 API 调用。
  • 后续搜索会复用 Agoda 缓存,并在约 30–60 秒内完成。

安全与数据处理

本地运行,无需 API 密钥,也不收集个人数据 — 唯一发送出去的数据是搜索查询(城市、日期、住客人数)。抓取的酒店文本视为不可信内容:bin/search.js 中的 sanitizeText() 会在任何内容传入模型输出前,移除控制字符、零宽字符、双向文本控制字符和 Markdown 控制字符;预订链接仅限 http(s)。

本地浏览器守护进程仅监听 loopback 地址并通过令牌进行身份验证(每次运行的令牌存储在 0600 状态文件中),会通过 DNS 重绑定拒绝非 loopback 的 Host 标头,并保持 Chromium 沙箱启用 — 仅在无法启用的情况下才使用 --no-sandbox(Linux 上以 root 身份运行,或显式设置 PRICEWIN_NO_SANDBOX=1)。

运行的命令、下载内容和网络出口的完整披露见 SECURITY.md。

评论

支持 Markdown