mcpField
S
sutochno

sutochno

github.com/borski生産性78040 回インストール2 日前に更新
リポジトリ

sutochno について

sutochno は、Sutochno.ru の短期賃貸物件を検索するコマンドラインスキルです。ジョージアやCISの宿泊先を探す旅行者向けに、都市ページを解析して絞り込み可能な結果とリンクを返しますが、予約は行いません。

主な機能

  1. 01都市サブドメインで物件を検索
  2. 02評価と1泊料金で絞り込み
  3. 03結果の並べ替えと重複除去
  4. 04JSONまたは表形式でリンクを出力

活用シーン

  1. 01トビリシやバトゥミの物件検索
  2. 02ルーブル建ての1泊料金で絞り込み
  3. 03予約前にオーナー直営物件を比較

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/borski/travel-hacking-toolkit --skill sutochno

インストール後、Claude Code で/sutochnoを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

Dockerfile
scripts/
entrypoint.sh
search_sutochno.py
tests/
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
引数
フラグデフォルト備考
--citycity/url のいずれかが必須都市のサブドメインキーワード。例:tbilisi、batumi。https://{city}.sutochno.ru/に解決されます。
--urlcity/url のいずれかが必須都市の完全なURL。クエリフィルターを含むページを渡す場合は、--cityの代わりに使用します。
--min-rating0クライアント側のフィルター。0~10の範囲です(例:9.0)。評価のない物件も含まれます。
--max-price0クライアント側の1泊あたりの上限価格(ルーブル)。価格のない物件も含まれます。
--limit20返す物件の最大数(並べ替え後)。
--headedoffブラウザーをヘッドありで実行します(デバッグ専用。Sutochnoにはボット対策の壁がないため、デフォルトはヘッドレスです)。
--jsonoffJSONを標準出力に出力します(オーケストレーションに使用します)。

セレクター(スクレイピングの契約)

都市ページでは、各リスティングカードに次の情報が含まれています。

フィールドセレクター生データの形式抽出方法
名前+リンク.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が返されます。サポート対象のアクセス先は、サーバー側でレンダリングされたページです。

コメント