amex-travel について
amex-travel は、Patchright で American Express 旅行ポータルのフライトやホテルを検索するスキルです。現金価格、MR ポイント、会員特典を比較でき、IAP 運賃や FHR・THC のホテル特典も識別します。画面表示ブラウザーが必要で、予約には対応しません。
主な機能
- 01フライトとホテルの検索
- 02現金価格と MR ポイントの比較
- 03IAP 割引運賃の識別
- 04FHR・THC のホテル特典抽出
- 05メールコードによるログイン
活用シーン
- 01ポータルのポイントと現金運賃の比較
- 02Platinum Card の IAP 割引検索
- 03FHR・THC ホテル特典の評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ borski/ travel-hacking-toolkit --skill amex-travelインストール後、Claude Code で/amex-travelを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
Dockerfilescripts/refresh_login.pysearch_flights.pytests/test_search_flights.py詳細
Amex 旅行ポータル検索
Patchright を介して American Express の旅行ポータルでフライトやホテルを検索します。現金価格、MR ポイント価格、International Airline Program(IAP)の割引、Fine Hotels & Resorts/The Hotel Collection の特典を取得します。
Patchright が必要です(検出を回避する Playwright のフォーク)。Amex は標準の Playwright と agent-browser をブロックします。
ヘッドありで実行する必要があります(headless=False)。 Amex はヘッドレスブラウザーを検出します。macOS では、Chrome ウィンドウが一時的に表示されます。バックグラウンドで実行する場合は、Docker を使用してください。
前提条件
pip install patchright && patchright install chromium
または、Docker を使用します(ローカルへのインストールは不要です)。
docker pull ghcr.io/borski/amex-travel:latest
# or build locally:
docker build -t amex-travel skills/amex-travel/
使用する場面
- Amex ポータルの MR 価格を、現金価格や特典航空券の価格と比較する
- Platinum の IAP(International Airline Program)割引運賃を探す
- 特典(100 ドルのクレジット、朝食、アップグレード)が付く FHR および THC のホテルを探す
- ポータルでのポイント利用価値を、航空会社へのポイント移行価値と比較する
使用しない場面
- 購入手続き。 フライトとホテルの検索のみ行います。予約はしないでください。
- Platinum 以外のカード。 IAP 運賃と FHR 特典には Platinum Card が必要です。
使い方
フライト検索
# Local (opens a Chrome window briefly)
python3 scripts/search_flights.py --origin SFO --dest CDG --depart 2026-08-11
# Round-trip business
python3 scripts/search_flights.py --origin SFO --dest CDG --depart 2026-08-11 --return 2026-09-02 --cabin business
# JSON output
python3 scripts/search_flights.py --origin SFO --dest CDG --depart 2026-08-11 --json
# Docker
docker run --rm \
-v ~/.amex-travel-profiles:/profiles \
-e AMEX_USERNAME -e AMEX_PASSWORD \
amex-travel script /app/search_flights.py \
--origin SFO --dest CDG --depart 2026-08-11 --cabin business --json
ホテル検索
# Local
python3 scripts/search_flights.py --hotel --dest "Oslo" --checkin 2026-08-13 --checkout 2026-08-15
# Docker
docker run --rm \
-v ~/.amex-travel-profiles:/profiles \
-e AMEX_USERNAME -e AMEX_PASSWORD \
amex-travel script /app/search_flights.py \
--hotel --dest "Oslo" --checkin 2026-08-13 --checkout 2026-08-15 --json
記録モード(API の調査)
手動検索中にネットワークトラフィックを記録します。
python3 scripts/search_flights.py --record
オフラインデバッグ(ホテル)
ブラウザーを再実行せずに、ホテルの検索結果を保存して再解析します。
# Save page HTML after hotel search
python3 scripts/search_flights.py --hotel --dest "Paris" --checkin 2026-08-11 --checkout 2026-08-15 --save-html /tmp/amex-hotels.json
# Re-parse locally (instant, no browser)
python3 scripts/search_flights.py --parse-html /tmp/amex-hotels.json
2FA フロー
Amex は 2FA にメールの OTP を使用します。「Add This Device」で初回ログインすると、同じプロファイルからの次回以降の実行では 2FA が省略されます。
仕組み: 2FA が要求されると、スクリプトは標準出力に 2FA_CODE_NEEDED、標準エラーに 2FA REQUIRED を出力し、コードをポーリングします。最大 2 分間待機します。
エージェント向け: スクリプトの出力に 2FA_CODE_NEEDED が表示されたら、Amex からメールで届いた確認コードをユーザーに尋ねてください。コードを受け取ったら、コードファイルに書き込みます。
echo "123456" > /tmp/amex-2fa-code.txt
スクリプトはファイルを自動的に検出し、ログインを続行します。
コマンドフック(任意、完全自動化向け): AMEX_2FA_COMMAND に、コードを取得するまでブロックし、その後コードを標準出力に出力するコマンドを設定します。スクリプトはファイルのポーリングの代わりに、このコマンドを実行します。
「Add This Device」で初回ログインすると、同じプロファイルからの次回以降の実行では 2FA が省略されます。
既知の制限事項:travel-portal のログイン CAPTCHA(2026 年 5 月)
Amex が 2026 年 5 月に大幅な改修を行って以降、フライト検索を送信すると、americanexpress.com にすでにサインインしている場合でも、リスクベースの CAPTCHA レイヤーで保護された別個の travel-portal ログイン画面(/account/travel/login)にリダイレクトされます。スクリプトはこの画面の入力と送信を自動で行いますが、その結果は、その実行時に Amex がセッションをどう評価するかによって異なります。
- 通過することもあります — 自動再認証が受け入れられ、検索結果が最初から最後まで読み込まれます(2026 年 7 月の実環境で検証済み:Docker での全工程実行で、解析済みフライト 50 件を取得)。
- 何事もなかったかのように処理されることもあります — 送信後もフィールドには正しい値が保持され、フォーム自体の
#loginSubmitがクリックされ、エラーは表示されず、CAPTCHA マーカーが DOM に存在するものの、ページは先に進みません。同日、同じ認証情報、同じコンテナで実環境で検証済みです。
また、travel セッションは有効期間が短く(next-auth トークンは約 1 時間)、ウォームセッションはすぐに期限切れになり、ログイン画面が頻繁に再表示されます。ログイン画面で失敗すると、スクリプトはフィールド/ボタン/アラートの状態を示す Gate diag: 行を出力するため、ログから問題を診断できます。その後、検索結果のタイムアウトを待たずに速やかに終了します。ホテル検索も同様の影響を受ける可能性があります。
この壁が現れるのは、新規ログイン時だけです。 保存済みのウォームセッション(有効な Cookie と信頼済みデバイス)があれば、ログイン画面は自動で通過し、検索を最初から最後まで実行できます。したがって、復旧には一度だけ人間による操作が必要ですが、行き止まりではありません。
-
ログイン画面で自動ログインが拒否された場合(CAPTCHA など)、スクリプトは標準出力に
AMEX_HUMAN_LOGIN_NEEDEDを出力し、/tmp/amex-2fa-status.txtにHUMAN_LOGIN_NEEDEDを書き込みます。エージェント向け: 再試行を停止し、ユーザーに更新スクリプトを実行するよう伝えてください。(別のセンチネルAMEX_BAD_CREDENTIALSは、認証情報の環境変数に実際の値ではなく、未解決のシークレットマネージャー参照が含まれていたことを示します。その場合はログインではなく、認証情報の受け渡しを修正してください。) -
ユーザーは Docker ではなくローカル環境で、次を実行します。
python3 scripts/refresh_login.py実際の Chrome ウィンドウが travel portal 上で開きます。ユーザー自身でログインし(パスワード、CAPTCHA、メールコード、「このデバイスを追加」)、スクリプトが更新済みの Cookie/プロファイルを自動的に保存します。完了すると
AMEX_SESSION_REFRESHEDが出力されます。 -
以降の実行では、
~/.amex-travel-profilesをマウントした Docker での実行も含め、ウォームセッションが再利用され、ログイン画面が省略されます。
セッションの期限切れを防ぐには、1~2 週間ごとに簡単な検索を実行するか、ログイン済みページを検出するとすぐ終了する refresh_login.py を実行してください。住宅用 IP の利用を推奨します。データセンターやホテルの IP は、Akamai による追加のチェックを受けやすくなります。
動作の仕組み
フライト検索のアーキテクチャ
- 認証: 保存済みプロファイルから Cookie を注入します。認証に失敗した場合は、新規ログインとメールによる 2FA に切り替えます。
- フォーム入力: DOM ベースで検索フォームを自動操作します(空港のオートコンプリート、カレンダーピッカー、客室クラスの選択)。
- ログイン画面: フォーム送信後、Amex はログイン用のインタースティシャル画面にリダイレクトします。スクリプトは再認証を自動的に処理します(リスクベース。既知の制限事項を参照)。
- データ抽出(新 UI、2026 年 5 月以降): 検索結果は
travel.americanexpress.com/en-us/book/flights/search-resultsに表示されます。ここは Next.js アプリで、利用可能なwindow.appDataはありません(__NEXT_DATA__は設定情報のみです)。スクリプトは DOM 内の[data-testid="offer-card-wrapper"]カードを解析します。航空会社、時刻、空港、所要時間、乗り継ぎ回数、現金価格、ポイント、変更前/変更後の割引には、それぞれ専用のdata-testidが付いています。 - データ抽出(従来 UI へのフォールバック): オファーカードが表示されない場合、スクリプトは従来の
window.appDataRedux ストアからの抽出に切り替えます(627 KB の JSON データ)。 - IAP の検出:
private-fare-banner-PEP*バナーがあり、現金価格が「$X から $Y」に割引されているカードは IAP(Platinum Member Airfares)です。通常、国際線の前方客室で 10~15%割引になります。Alaska の「Insider Fares」(ポイントのみの割引)は、insider_fare/points_discountで別途識別されます。
ホテル検索のアーキテクチャ
- フォーム入力: フライトと同じ DOM ベースの方法を使用します
- ログインゲート: 自動的に処理されます
- データ抽出: ホテルは Next.js アプリとして表示され、
window.appDataはありません。スクリプトはdata-testid="hotel-offer-card"要素を使って DOM を解析します。 - FHR/THC の検出:
data-testid="offer-banner"のテキスト(「Fine Hotels and Resorts」または「The Hotel Collection」)で判別します - 特典の抽出: FHR/THC のカードには、特典(朝食、クレジット、アップグレード)が
data-testid="offer-amenities-item"要素として表示されます
データ構造
フライトの検索結果(window.appData.flightSearch.itineraries[] から取得):
fare_typeがPEP(IAP)またはPUB(一般運賃)のpricing_information[]total_price.cents(現金)、total_price_in_points(MR ポイント。1 ポイントあたり 1 セント)- 航空会社、時刻、所要時間、客室クラス、機材、アメニティを含む
segment.legs[] segment.seats_left、is_refundable、cancellation_policy
ホテルの検索結果(DOM 解析から取得):
- ホテル名、星の数、都市、距離
- TripAdvisor の評価と口コミ数
- 1 泊あたりの料金と合計料金
- MR ポイントの必要数
- FHR/THC 会員特典と具体的な内容
- 標準的なアメニティ(Wi-Fi、朝食、駐車場)
International Airline Program(IAP)
Platinum Card の特典です。対象航空会社の国際線プレミアムキャビンを割引運賃で利用できます。PUB(一般運賃)と並んで、別の PEP 運賃タイプとして表示されます。
- ビジネスクラス/ファーストクラスで通常 10~15%の割引
- すべての路線や航空会社が対象ではありません
- Platinum Card でログインしている場合にのみ表示されます
出力形式
必ず Markdown の表を使用してください。
フライト
| # | 航空会社 | 路線 | 経由回数 | 所要時間 | 現金 | IAP 現金 | ポイント | 残席数 |
|---|---|---|---|---|---|---|---|---|
| 1 | Turkish | SFO-IST-CDG | 1 | 20h 10m | $5,044 | $4,381 | 438,113 | 3 |
ホテル
| # | ホテル | プログラム | 星の数 | 1 泊あたり | 合計 | ポイント | 特典 |
|---|---|---|---|---|---|---|---|
| 1 | Hotel Continental | FHR | 5 | $471 | $942 | 94,200 | 朝食、$100 のクレジット、アップグレード、午後 4 時のチェックアウト |
表の後に記載する内容
- IAP の割引額を示します(割引率も表示)
- FHR/THC の特典と、料金をどのように補えるかを記載します
- MR ポイントでの交換における実質的な CPP を計算します(Amex ポータルでは 1 ポイント=1 セント)
- 航空会社への移行による価値と比較します
- Platinum の年間 $600 のホテルクレジットについて記載します(半年ごとに $300、FHR と THC で共用)
客室クラスコード
| CLI の値 | Amex コード | 説明 |
|---|---|---|
economy | ECONOMY | エコノミークラス |
premium | PREMIUM_ECONOMY | プレミアムエコノミー |
business | BUSINESS | ビジネスクラス |
first | FIRST | ファーストクラス |
環境変数
| 変数 | 必須 | 説明 |
|---|---|---|
AMEX_USERNAME | はい | Amex オンラインアカウントのユーザー名 |
AMEX_PASSWORD | はい | Amex オンラインアカウントのパスワード |
AMEX_PROFILE | いいえ | ブラウザプロファイルのディレクトリ(デフォルト:~/.amex-travel-profiles/default) |
AMEX_2FA_COMMAND | いいえ | メールのコードが使用可能になるまで待機し、そのコードを標準出力に出力するコマンド |
トラブルシューティング
- 検索後にログインゲートが表示される: 正常です。Amex はフォーム送信後、必ずログイン用の中間ページにリダイレクトします。スクリプトが自動的に処理します。
- appData が見つからない(フライト): ページの読み込みが完了していない可能性があります。スクリプトは Redux ストアが読み込まれるまで待機します。ログインが成功したか確認してください。
- ホテルの検索結果が空: ホテルは appData ではなく DOM を解析します。DOM の構造が変更された場合、
data-testidセレクターの更新が必要になることがあります。 - カレンダーピッカーが動作しない: Amex はカレンダーの日付に
<button>ではなくdiv[role="button"]を使用します。スクリプトはクラスパターンautomation-date-picker-month-{year}-{month}を使って、該当する月のコンテナーを見つけます。 - 2FA コードが拒否される: Amex のコードはすぐに期限切れになります。新しいコードであることを確認してください(前回のログイン時の古いコードは使用しないでください)。
制限事項
- ヘッド付きモードが必要です。 Amex はヘッドレスモードを検知します。回避策は Docker+xvfb です。
- 検索1回あたり約45秒かかります。 ログイン+フォーム入力+ログインゲート+結果の読み込みにかかる時間です。
- ホテルの検索結果は DOM のみから取得します。 ホテルでは API インターセプトを利用できません(
__NEXT_DATA__が空の Next.js アプリです)。パーサーはdata-testid属性に依存します。 - デバイスの信頼登録が役立ちます。 初回ログイン時に「このデバイスを追加」を選択すると、そのプロファイルでは 2FA がスキップされます。Docker のボリュームマウントを使ってプロファイルを永続化してください。