关于 sutochno
sutochno 是用于搜索 Sutochno.ru 短租房源的命令行技能,适合寻找格鲁吉亚及其他 CIS 目的地住宿的旅客。它抓取城市页面并提供可筛选、排序的结果和链接,但不负责预订。
主要功能
- 01按城市子域名搜索房源
- 02按评分和每晚价格筛选
- 03对结果排序并去重
- 04以 JSON 或表格返回房源链接
适用场景
- 01查找第比利斯或巴统住宿
- 02按卢布每晚价格筛选住宿
- 03预订前比较房东直租房源
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ borski/ travel-hacking-toolkit --skill sutochno安装后在 Claude Code 中输入/sutochno确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
Dockerfilescripts/entrypoint.shsearch_sutochno.pytests/test_search_sutochno.py详细介绍
Sutochno 搜索
搜索 Sutochno.ru(СУТОЧНО.РУ)——一个俄罗斯短租市场平台,用户可以直接向房东预订公寓、房间和房屋,并以卢布付款,通常使用 Mir 卡或银行转账。对于预订格鲁吉亚 / 独联体住宿的俄语旅客来说,这是很自然的选择,因为 Airbnb 和 Booking 已撤出,或不接受俄罗斯银行卡。它可与 Airbnb MCP 和 vrbo 技能搭配使用:前者覆盖西方房源,Sutochno 则能找到这些平台遗漏的卢布定价、房东直租房源。
Sutochno 不受 Akamai 保护。 与需要应对 Akamai 反机器人墙、必须以有头模式运行的 vrbo 技能不同,Sutochno 的服务端渲染城市页面在无头模式下也能正常加载——无需绕过机器人检测机制。此技能仍基于工具包标准的 patchright-docker 镜像构建(与其他浏览器技能使用相同镜像),但仅用于提供捆绑的 chromium 和 OS 依赖;它不需要 Patchright 的隐身功能。Patchright 是 Playwright 的直接替代分支,因此浏览器 API 相同。默认使用无头模式;--headed 可用于调试。
JSON API 需要身份验证——因此我们改为抓取页面。 Sutochno 的 /api/* 端点(例如 /api/geo/suggest)如果没有 SPA 在客户端计算的应用令牌,就会返回 403 Application authentication failed。因此,此技能不会调用 API,而是抓取服务端渲染的城市页面,其中房源卡片已包含在 HTML 中。
城市搜索结果位于子域名上。 每个城市都有自己的主机名:
https://tbilisi.sutochno.ru/、https://batumi.sutochno.ru/、
https://kutaisi.sutochno.ru/ 等。国家目录
https://sutochno.ru/georgia 会列出格鲁吉亚支持的城市,并链接至
https://{city}.sutochno.ru/<listingId> 房源卡片。传入城市作为
子域名关键词(--city tbilisi),或传入完整 URL(--url)。
无需登录。 Sutochno 的搜索结果公开可见;此技能会查找出租房源并返回链接,不会登录或完成预订。
前置条件
pip install patchright && patchright install chromium
或使用 Docker(无需本地安装):
docker build -t sutochno skills/sutochno/
适用场景
- 俄语旅客(或与俄语同伴同行的旅客)预订通过 Mir 卡或银行转账以卢布支付的住宿
- 预订格鲁吉亚 / 独联体住宿(第比利斯、巴统、库塔伊西等),而 Airbnb / Booking 已撤出或不接受俄罗斯银行卡
- 预订多晚住宿前,将房东直租的卢布计价房源与 Airbnb / VRBO 进行交叉对比
不适用场景
- 完成预订。 此技能只查找出租房源并返回链接。不要尝试完成购买或联系房东。
- 独联体以外的目的地。 对于西方目的地,Airbnb(MCP)、
vrbo技能和 Booking 的房源更丰富、银行卡支持也更完善——请使用这些平台。 - 酒店 / 品牌连锁酒店。 请使用 compare-hotels / serpapi / liteapi / 门户技能。
用法
# Tbilisi, human-readable table (headless by default)
python3 skills/sutochno/scripts/search_sutochno.py --city tbilisi
# Batumi, JSON, only 9.0+ rated, under 8000 rubles/night, top 15
python3 skills/sutochno/scripts/search_sutochno.py --city batumi \
--min-rating 9.0 --max-price 8000 --limit 15 --json
# Explicit full URL (e.g. a city page with query filters already applied)
python3 skills/sutochno/scripts/search_sutochno.py \
--url "https://kutaisi.sutochno.ru/" --json
# Docker
docker run --rm sutochno --city tbilisi --json
参数
| 标志 | 默认值 | 说明 |
|---|---|---|
--city | city/url 必填其一 | 城市子域名关键词,例如 tbilisi、batumi。解析为 https://{city}.sutochno.ru/。 |
--url | city/url 必填其一 | 完整城市 URL——如果要传入已包含查询筛选条件的页面,请使用此参数代替 --city。 |
--min-rating | 0 | 客户端筛选,评分范围为 0–10(例如 9.0)。保留没有评分的房源。 |
--max-price | 0 | 客户端筛选,每晚卢布价格上限。保留没有价格的房源。 |
--limit | 20 | 返回的房源数量上限(排序后)。 |
--headed | off | 以有头模式运行浏览器(仅用于调试——Sutochno 没有机器人墙,因此默认使用无头模式)。 |
--json | off | 将 JSON 输出到 stdout(用于编排)。 |
选择器(抓取契约)
在城市页面上,每个房源卡片包含:
| 字段 | 选择器 | 原始格式 | 提取方式 |
|---|---|---|---|
| 名称 + 链接 | .card-content__object-type(一个 <a>) | 文本 + href → https://{city}.sutochno.ru/<id>(或 /hotels/<id>) | 名称文本;id = href 末尾的数字 |
| 价格 | .card-prices__price | "4 890 ₽ за сутки" | 取 ₽ 之前的子字符串,去掉所有非数字字符 → 4890 |
| 评分 + 评论数 | .card-prices__rating | "10 отзывов 9,8 (10) …" | 评分 = 首个 /\d{1,2},\d/(逗号 → 点);评论数 = /(\d+)\s*отзыв/ |
| 地址 | .card-content__address | "Тбилиси, Старый город" | 原样提取 |
卡片包装元素是名称节点最近的、同时包含 .card-prices 元素的祖先——名称和价格是同级元素,而非嵌套关系。因此,提取器会从名称链接开始向上遍历,直到 el.querySelector('.card-prices') 为真,然后从该包装元素内读取价格和评分。
价格注意事项:价格字符串中的千位分隔符是混合宽度/不换行空格,因此简单的 \d+ 正则会截掉首位数字(对 4 890 返回 890)。可靠的方法是按 ₽ 分割,再去掉所有非数字字符——这正是 parse_price 的处理方式。
图片是延迟加载的占位图(首次渲染时为 lzy-img.gif),因此抓取器不依赖照片。
输出
使用 --json 时的 JSON 结构:
{
"source": "sutochno",
"searchUrl": "https://tbilisi.sutochno.ru/",
"query": { "city": "tbilisi", "url": null, "min_rating": 9.0, "max_price": 8000 },
"count": 12,
"listings": [
{
"id": "1234567",
"name": "Уютная студия в центре",
"area": "Тбилиси, Старый город",
"rub_per_night": 4890,
"rating": 9.8,
"reviews": 10,
"url": "https://tbilisi.sutochno.ru/1234567"
}
]
}
房源按 id 去重,并按评分降序、再按价格升序排序(没有评分/价格的条目排在最后)。rub_per_night 是以卢布计价的每晚起始价格——请打开房源 URL 确认总费用(清洁费、押金以及房东收取的其他费用可能未计入搜索结果页面的价格)。
测试
纯逻辑(城市 URL 构建、卢布价格解析、评分/评论数解析、房源 ID 提取、标准化、去重/筛选/排序)由标准库 unittest 测试覆盖——无需浏览器、网络或 Patchright(patchright 采用延迟导入):
python3 -m unittest discover -s skills/sutochno/tests -v # or: python3 -m pytest skills/sutochno/tests
浏览器驱动的流程(页面导航、DOM 提取)无法离线进行单元测试——请通过真实的城市搜索进行验证(参见上文“用法”)。
已知脆弱点
- **DOM 选择器可能发生变化。**Sutochno 可能会修改
card-content__*/card-prices__*类名。如果在已知有房源的城市进行实时搜索时返回 0 张卡片,请重新检查城市页面,并更新EXTRACT_JS和上方的选择器表(提交一个 P2 任务)。 - **API 仍受身份验证限制。**不要尝试重新使用
/api/*——它需要 SPA 计算得出的应用令牌;没有该令牌时会返回403 Application authentication failed。服务端渲染页面才是受支持的接口。