「Expedia ね、はいはい、Playwright + stealth で行けるでしょ」と思っていた半年前の自分に教えてあげたい。そんな甘い世界じゃない、ということを。
私たちは swimple(スウィンプル)という ホテル価格監視サービス を運用しています。6 つの主要なホテル予約サイト ── 楽天トラベル・じゃらん・Booking.com・Expedia・Agoda・Trip.com ── を横断してホテルの空きプランと最安料金を取得し、登録ホテルの値下がりや在庫変化をメールで通知する という、シンプルなサービスです。
「6 つのホテル予約サイトをスクレイピングする」と書くと簡単そうに聞こえます。実際、5 つまでは比較的すんなり動きました。
問題は Expedia です。
Expedia の bot 対策は、他のホテル予約サイトとは まったく次元が違います。
- Playwright を stealth プラグインで武装しても止まる
- residential IP を経由しても止まる
- Cookie を完璧に持ち回っても、24時間で人間認証(あの「Press & Hold」のボタン)が出る
- ヘッドレスを諦めて headed Chrome にしても、それでも捕まる
その背景にいるのが Akamai Bot Manager Premier(Akamai BMP) です。
この記事は、swimple を作るために Expedia と戦った半年で見えてきた、
- 何を試して何がダメだったか(失敗集)
- Akamai BMP は何を見ているのか を、観察と推測でどこまで詰められたか
- Expedia の bot 対策はなぜここまで強いのか、その設計思想の推測
を書き残したものです。
半年経った今、swimple は Expedia を含む 6 つのホテル予約サイトを毎日安定して取得しています。どうやって? ── は、記事の最後で、Akamai BMP の設計思想に対する 敬意のかたち として、少しだけ触れます。
これからスクレイピングを業務で扱う人 ── 特にホテル予約サイトや EC、予約系を相手にする人にとって、「ここまでやってる相手がいる」という 地図 として読んでもらえたら幸いです。
ホテル予約サイト 6 社の bot 対策 難易度マップ
「6 つのホテル予約サイトをスクレイピング」と言ったとき、各サイトがどれくらい難しいかは まったく均一ではありません。半年触ってきた体感を、★ 1〜5 で並べてみます。
★1: 楽天トラベル
そもそも公式 API がある ので、スクレイピングする必要がない、というレベル。Rakuten Travel Vacant Hotel Search API が無償で叩けます。レスポンスは JSON、ドキュメントも揃っている。ありがたい。
取得遅延もなく、安定して動く。「普通」とはこういうことだったか、と他社で苦戦してから気づかされました。
★1: じゃらん
公式 API はないが(厳密にはアフィリエイト用エンドポイントはある)、HTML スクレイピングが 素直に動く。bot 対策は最低限で、Cookie や User-Agent をそれっぽくしておけば 200 が返ってきます。HTML 構造もそれなりに安定していて、月に一度くらいセレクタを微調整する程度の保守で済んでいます。
★2: Trip.com
JS レンダリングが必要なページが多く、Playwright で動かす必要がある。ただし bot 対策は控えめで、適切な headless + User-Agent でほぼ通る。アフィリエイトプログラムも整備されており、API 的に扱うこともできる。「真っ当な相手」 という印象。
★3: Booking.com
HTML スクレイピングは可能だが、bot 対策が一段強い。明らかな headless はブロックされ、IP 単位での rate limit も厳しい。Cookie の取り回しと User-Agent の慎重な選定で乗り切れるレベル。「ちゃんと気を遣えば動く」 という感じで、初見だと「これがハードか」と思う。でも Expedia を見ると、これは中堅でしかなかったと気づきます。
★4: Agoda
ここから空気が変わります。
bot 検知が高度で、headless Chrome は即座にブロックされる。Playwright + stealth プラグインを盛っても、リクエストを重ねるうちにあっさり弾かれる。さらに 間欠的に bad gateway や anti-bot challenge が混ざるため、リトライ戦略も単純ではない。「平均的に動くけど、瞬間最大風速の失敗率が高い」というタイプの相手。
我々はここで一度、「サーバ側からの取得を諦めて、別の経路に切り替える」 判断を迫られました。これは後の章で。
★5: Expedia ── 別カテゴリ
そして Expedia。★5 でも足りないくらいです。★1〜★4 が同じ軸の上にいるとすれば、Expedia は完全に 違う軸 にいます。
- 単純な Playwright + stealth → すぐにブロック
- Cookie を完璧に持ち回り → 24 時間で人間認証(Press & Hold)
- residential IP を経由しても → セッションの「深さ」を見られて bot 判定
- headed Chrome を裏で動かしても → ブラウザ fingerprint で捕まる
その正体が Akamai Bot Manager Premier(Akamai BMP) です。
世界の主要 EC・予約・金融サイトの多くが導入している、bot 対策の事実上の最高水準。Expedia はこれを「普通の宿泊予約サイト」の前段に挟んでいます。執念を感じる。
次の章では、この Akamai BMP が「何を見ているのか」、半年の試行錯誤で見えてきたことを書きます。
Akamai BMP は何を見ているのか ── 半年の観察と推測
ここからは、半年間の試行錯誤で見えてきた Akamai BMP の挙動について整理します。Akamai 社は内部仕様を公開していないので、すべては 外から触った結果の像 です。「観察した事実」 と 「推測」 はなるべく区別して書きます。
観察1: _abck Cookie だけでは足りない
Akamai 環境で最も有名な cookie が _abck です。「これさえあれば通る」と書かれている古い記事をいくつか見ました。
実際には全然そんなことはありません。
_abck を完璧に新鮮な状態で持っていても、サーバ側で Playwright から取得しようとすると 429 や challenge ページが返ってきます。_abck は 結果として有効になっている cookie であって、「持っていれば通る token」ではない ようです。
おそらく Akamai 側では、_abck の中身を評価しているのではなく、その cookie がどういう経路・どういう挙動の中で発行されたか を別の軸で見ている。
観察2: セッションの「成立のしかた」を見られている
Akamai BMP 下のページに最初にアクセスすると、cookie はすぐ降ってきます。が、その cookie で別のページに直接アクセスすると弾かれる ことがある。
色々試した範囲では、cookie をどう発行させ、その cookie がどう使われるか によって、後続のリクエストの通り方が大きく変わるように見える。「cookie を持っている」ことと、「Akamai 側で『正規ユーザのもの』と認められている cookie を持っている」ことは別物 で、後者にするための条件は単純ではない。
何が「認められる cookie」を作るかは、観察できる範囲では複合的な条件で決まっているように見える、というところまで。
観察3: 24時間サイクルの存在
これは多くの人が普通にブラウザを使っていても遭遇する有名な現象ですが、Expedia は だいたい 24 時間経つと、人間認証(Press & Hold ボタン)を出してきます。ログイン状態かどうかは関係なし。
スクレイピング側にとって厄介なのは、24 時間ごとに「ボットではない」ことを証明し直さないと、それ以降のリクエストが全部止まる こと。チャレンジを出されたあとの cookie は、解かないと 「腐った」状態 になるらしく、新規セッションを最初からやり直してもしばらく challenge が連発します。
観察4: ヘッドレスはほぼ即バレる
Playwright や Puppeteer の headless mode は、navigator.webdriver のような有名なフラグだけでなく、ブラウザの様々な内部状態を組み合わせた指紋 で識別されます。レンダリング、音声、描画系の細かいシグナルまで取られている、というのは Akamai / PerimeterX 関連の公開記事でも触れられている話。
「playwright-stealth 入れれば OK」というのは数年前の話で、Akamai BMP 環境では現在ほぼ通用しません。stealth でフラグの一部を消しても、消し方そのものが指紋になっている ── というのが正直なところです。
観察5: cookie や IP 以外のシグナルも見られている(らしい)
これは確信ではなく強い推測ですが、Akamai BMP は cookie や IP 以外のシグナルも収集しているように見えます。
根拠としては、同じ cookie・同じ IP・同じブラウザを使っていても、そのセッションがどう「成立した」かによって、その後の結果が変わると感じる場面が何度もあったこと。「cookie が同じなら同じ判定」とは明らかになっておらず、何か追加の評価軸がある。それが具体的に何なのか、外から見ているだけでは完全には特定できていません。
推測: 設計思想
ここまで観察してくると、Akamai BMP の設計思想が おぼろげに 見えてきます。我々の解釈は次の通り。
Akamai BMP は、単発のリクエストではなく「セッション全体の自然さ」をスコアリングしている。
各リクエストを「pass / fail」で判定するのではなく、そのセッションがどれだけ「普通の人間がブラウザを使っているように見えるか」 を、cookie・fingerprint・header・経路・時間軸の全部を統合してスコア化している。スコアが閾値を下回ったら challenge を投げる、というデザイン。
つまり勝つには「1 リクエストごとに偽装する」のではなく、「セッション全体を本物っぽく振る舞わせる」必要がある。
そしてその「本物っぽさ」のうち、最後の数 % は人間でないと出せない領域 にある ── というのが、半年戦って見えてきた結論です。
試して効かなかったこと ── 失敗集
ここまで「Akamai BMP すごい」だけだとフェアじゃないので、実際に試して効かなかったアプローチ を並べます。多くの開発者が同じ罠にハマるはずなので、誰かの時短になれば。
失敗1: 「Playwright + stealth で行けるでしょ」
半年前の自分。「ハイハイ」と言って playwright-stealth を入れて Expedia を開いて、即 challenge。記事タイトルどおり「心折られた」記念すべき第 1 回。最初の 30 分で起きます。
失敗2: User-Agent をモバイル風に変えてみる
通った気がする → 数十リクエスト後にやっぱり弾かれる。
User-Agent はもはや「最低限の入り口」 であって、それ単体で勝てる時代は完全に終わっている。
失敗3: residential proxy を契約して通す
品質の良い residential proxy(月数万円〜)を入れたら通り始めた、と一瞬喜ぶ。でも 1〜2 日後に同じ proxy IP が challenge を返すように。
IP の質は確かに重要だが、IP「だけ」では不十分。
失敗4: 完璧な Cookie の持ち回り
本物のブラウザでアクセスして cookie を全部 export、それをスクレイパに渡す。動く。動くが、24 時間で人間認証が出てくる。cookie は鮮度ではなく、その後の振る舞いとセットで評価されている。
失敗5: headless やめて headed Chrome を裏で動かす
ヘッドレスの fingerprint バレが原因なら、本物の Chrome を --remote-debugging-port で操作すれば? → CDP の存在自体が見られている。Chrome を「操作されている状態」にした瞬間に痕跡が残る。
失敗6: JS challenge を読んで自前で実装
降ってきた JS challenge を読み解いて、自前のエミュレータで応答を生成する戦略。これは できなくはない。が、翌週には Akamai がコードを差し替えてきて、その翌週には別の経路に変わる。維持コストが地獄。
失敗7: CAPTCHA solver サービスに丸投げ
2Captcha や CapSolver のような有償サービスに challenge を投げる。reCAPTCHA や hCaptcha は対応していても、Akamai 系の Press & Hold は対応外、または極端に料金が高い サービスがほとんど。そして仮に解けても、解いたあとの cookie が「腐っていない」とは限らない。
失敗8: TLS fingerprint を偽装するライブラリを噛ませる
curl-impersonate や Go の utls で、本物の Chrome のように TLS ハンドシェイクを再現する。これは 部分的には効く。が、結局 cookie・JS・行動の検査が後段で待っているので、TLS だけ通ってもその先で詰む。
失敗9: リクエスト間隔を空ければ優しくなると思う
スリープを長くして「遅く優しく叩く」。これは効かない。Akamai BMP は速度ではなく 深さと自然さ を見ているので、1 時間に 1 リクエストでも、薄いセッションは即捕まる。
共通点
ここに並んだ失敗には ひとつ共通点 があります。どれも「Web リクエストとして見たときの偽装」を試みている ということ。
User-Agent を変えるのも、TLS を偽装するのも、cookie を持ち回るのも、全部「リクエストとしての見た目」のレイヤーの話です。Akamai BMP はそこを見ていない ── というのが、何度も心を折られて我々が出した結論でした。
設計思想の推測 ── Akamai BMP は何を守ろうとしているのか
我々が試した失敗の ほぼ全部 は「リクエストとしての見た目を偽装する」アプローチでした。それが効かなかったということは、Akamai BMP の発想はそこにはない、ということになる。
ではどこにあるのか。半年戦った末に辿り着いた我々の解釈はこうです。
「リクエスト」ではなく「セッション」を評価している
従来の bot 対策は、1 リクエストごとに「正規 / 不正」を判定するモデルでした。User-Agent が変、IP が変、Referer が無い、JS が動かない、等の単発のシグナルで弾く。
Akamai BMP の発想はその延長ではなく、「このユーザは過去数十秒〜数十分のあいだ、どう振る舞ってきたか」を全体として見る、というモデルに見えます。
cookie・fingerprint・TLS・header・IP は、そのセッションを識別するためのキー でしかなく、判定そのものはセッションが累積したシグナルに対して行われる。
これは bot 対策の問題定義そのものを書き換えています。「これは bot ですか?」ではなく、「このセッションは人間の使い方として自然ですか?」を問う設計。
攻撃側と防御側の非対称性
この設計が美しいのは、防御側のコストが安く、攻撃側のコストが高い という非対称性を生んでいる点です。
防御側は、ユーザの自然なブラウザ操作から「人間らしさ」のベースラインを学習し、それと比較するだけでよい。普通のユーザが普通に Expedia を使っている時点で、教師データが無限に集まる。
一方、攻撃側は「人間らしい振る舞い」を 作為的に演出する必要がある。マウスの軌跡、スクロールのタイミング、ページ間の滞在時間 ── これらを「人間らしく見える」ように合成する。が、合成は必ず指紋を残し、Akamai 側で蓄積された「本物」とのズレが見えてしまう。
人間を模倣するコストは、人間を観察するコストより常に高い。これがこの設計の根っこにある思想だ、と我々は理解しています。
スケールするからこそ強い
Akamai BMP は世界中の大規模サイト(航空券・ホテル・銀行・EC・チケット転売対策)に導入されています。これにより、「人間ユーザの操作プロファイル」のデータベースは Akamai 側に巨大な規模で蓄積されている。
新しい攻撃手法が登場しても、それが「Akamai 顧客全体で観測される異常パターン」になった瞬間に、全顧客で同時にブロックされる。攻撃者は 1 サイトの突破に時間をかけても、横展開した瞬間に死ぬ 仕組み。
これは攻撃側にとって絶望的な構造です。1 つのバイパスは 1 つしか使えない。
では「本物の人間」をどう扱っているのか
ここまで読むと、「真面目なユーザでも誤検知されないの?」と疑問が出ます。
実は、ある程度の閾値で誤検知を許容している ように見えます。普通のユーザが時々 Press & Hold に遭遇するのは、ボーダーラインに乗った結果。スクリプトを書く側にとっては challenge ですが、真面目なユーザにとっては「5 秒指で押すだけ」のちょっと面倒なステップ で済む。
防御側はこの 「人間にとってはわずかに面倒で、bot にとっては致命的」 という非対称をうまく利用しています。人間は 5 秒指で押すだけで通れる。bot にはそれが極めて難しい。
このバランスを設計した人達、本当によく考えていると思う。
では swimple はどうしたのか ── 発想の転換
ここまで「Akamai BMP すごい」と褒め続けてきましたが、実際 swimple は Expedia を半年以上、毎日安定して取得し続けています。
ということは、何かしら通る道はある、ということです。具体的な実装はここでは書きません。代わりに、半年戦って辿り着いた 発想の転換 だけ書き残しておきます。
「人間に近づこうとする」のをやめた
「失敗集」で並べた失敗の共通点は、「人間っぽく見せようと頑張る」アプローチでした。
- スクリプトを人間っぽく振る舞わせる
- マウスを人間っぽく動かす
- 滞在時間を人間っぽく演出する
すべての出発点が「bot である自分が、いかにして人間に化けるか」。
我々がぶつかった結論は、この方向では Akamai BMP に勝てない、というものでした。前章で書いたとおり、人間を模倣するコストは、人間を観察するコストより常に高い。スコアリングモデルに対して合成で挑む限り、最終的には負ける。
ではどうしたか。
「模倣する」のをやめて、「合わせる」発想に切り替えた
辿り着いた発想は、おおまかにこうです。
Akamai BMP が「本物の人間のセッション」を通すように設計されているなら、こちら側の戦い方も「bot として偽装する」ではなく、「Akamai BMP が想定している世界の側に立つ」になる。
抽象的な言い方ですが、この方針転換のあと、Akamai BMP との関係が「システムをどう騙すか」ではなく、「システムが期待する流れの中で、自分の必要なデータをどう拾うか」に変わりました。
書ける範囲だけ、設計レベルのキーワードを置いておきます。
- 「リクエスト単位での偽装」を捨て、セッション全体としての扱いに振る
- 「何で取りに行くか」より「いつ・どう取りに行くか」の設計に重心を置く
- Akamai BMP は 倒すべき敵ではなく、設計の前提 として組み込む
- 出てくる challenge は、出る前に避けようとしない(出たら自動で復帰 できるように作る)
これだけ書くと「結局よくわからない」と思われるかもしれません。それはその通りで、「具体的にどう作っているか」を書かないと意味は伝わらない、というのも本音です。ここでは方針までで止めておきます。
結果として何が起きたか
このアプローチに振り切ってから、半年以上が経ちました。swimple の Expedia 取得は今、
- 数千リクエスト規模で日々安定稼働
- challenge は時々出るが、出ても自動で復帰
- ブロック起因のサービス停止はゼロ
- 楽天トラベルや じゃらん と 同じ運用粒度 で扱えている
という状態です。Akamai BMP に勝った、と言うつもりは全くありません。勝ったのではなく、ぶつからない場所に立っている、というのが正確な表現です。
そしてこの「ぶつからない場所」を見つけるのに、半年と数えきれない失敗が必要でした。
終わりに ── swimple とお問い合わせ
Expedia をスクレイピングしようとして Akamai BMP に何度も心折られた半年でしたが、振り返ってみると Akamai BMP の設計の良さを学んだ半年でもあった と思います。
「セッション全体をスコアする」という発想、「人間を観察し、模倣を弾く」という非対称性 ── これらは bot 対策に限らず、Web セキュリティの設計思想として通用する考え方だと感じています。
swimple について
この記事を書いた swimple は、ホテル予約サイト 6 社を横断したホテル価格監視サービス です。
- ホテル名を 1 つ入れるだけで、楽天トラベル・じゃらん・Booking.com・Expedia・Agoda・Trip.com の最安料金をまとめて比較
- 登録したホテルの値下がりや在庫変動を メールで自動通知
- 完全無料(全機能をどなたでも無料で使えます)
予約予定のホテルがあるなら、ぜひ一度試してみてください。
お問い合わせ
- swimple サイト: https://swimple.net
- X: @swimple_app
- note: note.com/swimple
- メール: contact@swimple.net
以下の 2 種類のご相談を募集しています。
1. ホテルの価格を継続的にウォッチしたい法人の方
出張規程の見直し、競合ホテルの価格動向調査、社員旅行や研修向け宿泊プランの最適化、自社運営ホテルの市場価格モニタリングなど ── ホテル予約サイトの価格データを業務に活かしたい法人の方、お気軽にご相談ください。データの定期提供、カスタム集計レポート、API 提供などの形で対応できます。
2. Web サイトのスクレイピング・データ取得の開発相談
特に 「普通の Playwright では取れない難物」 が得意分野です。
ホテル・EC・予約・チケット系など、anti-bot が厳しいサイトでお困りの方、技術相談だけでも歓迎します。
最後まで読んでいただきありがとうございました。半年で数えきれない失敗をしましたが、たぶん次の失敗もすぐに来ます。それでも書き続けます。