sutochno について
sutochno は、Sutochno.ru の短期賃貸物件を検索するコマンドラインスキルです。ジョージアやCISの宿泊先を探す旅行者向けに、都市ページを解析して絞り込み可能な結果とリンクを返しますが、予約は行いません。
主な機能
- 01都市サブドメインで物件を検索
- 02評価と1泊料金で絞り込み
- 03結果の並べ替えと重複除去
- 04JSONまたは表形式でリンクを出力
活用シーン
- 01トビリシやバトゥミの物件検索
- 02ルーブル建ての1泊料金で絞り込み
- 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 Search
Sutochno.ru(СУТОЧНО.РУ)を検索します。ここはロシアの短期賃貸マーケットプレイスで、オーナーからアパート、部屋、一軒家を直接予約し、通常はMirカードまたは銀行振込でルーブル払いします。ロシア語を話す旅行者がジョージア/CISで宿泊先を予約するのに適しています。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が撤退している、またはロシアのカードを受け付けていないジョージア/CISへの滞在(トビリシ、バトゥミ、クタイシなど)
- 複数泊の滞在を予約する前に、オーナーが直接貸し出すルーブル建ての物件をAirbnb/VRBOと照合する場合
使用しない場面
- **予約の完了。**このスキルは賃貸物件を検索してリンクを返すだけです。購入を完了したり、オーナーに連絡したりしないでください。
- **CIS以外の旅行先。**欧米の旅行先では、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 | クライアント側の1泊あたりの上限価格(ルーブル)。価格のない物件も含まれます。 |
--limit | 20 | 返す物件の最大数(並べ替え後)。 |
--headed | off | ブラウザーをヘッドありで実行します(デバッグ専用。Sutochnoにはボット対策の壁がないため、デフォルトはヘッドレスです)。 |
--json | off | JSONを標準出力に出力します(オーケストレーションに使用します)。 |
セレクター(スクレイピングの契約)
都市ページでは、各リスティングカードに次の情報が含まれています。
| フィールド | セレクター | 生データの形式 | 抽出方法 |
|---|---|---|---|
| 名前+リンク | .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はルーブル建ての1泊あたりの基本料金です。合計料金(清掃費、デポジット、オーナー手数料など)が検索結果の表示額に含まれていない場合があるため、リスティングの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が返されます。サポート対象のアクセス先は、サーバー側でレンダリングされたページです。