mcpField
A
amex-travel

amex-travel

github.com/borski其他78069 次安装2 天前更新
代码仓库

关于 amex-travel

amex-travel 是通过 Patchright 搜索 American Express 旅行门户航班和酒店的技能,面向需要比较现金、MR 积分及会员权益的 Amex 持卡人。它可识别 IAP 票价及 FHR、THC 酒店福利;需要有头浏览器,且不支持预订。

主要功能

  1. 01搜索航班与酒店报价
  2. 02比较现金价格与 MR 积分
  3. 03识别 IAP 折扣票价
  4. 04提取 FHR、THC 酒店福利
  5. 05支持邮箱验证码登录

适用场景

  1. 01比较门户积分与现金机票价格
  2. 02查找 Platinum 卡 IAP 折扣
  3. 03评估 FHR 或 THC 酒店权益

安装

复制下面的命令,在终端中运行。

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

安装后在 Claude Code 中输入/amex-travel确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

Dockerfile
scripts/
refresh_login.py
search_flights.py
tests/
test_search_flights.py

详细介绍

Amex Travel Portal 搜索

通过 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)折扣票价
  • 查找享有礼遇的 FHR 和 THC 酒店(100 美元额度、早餐、升级)
  • 比较门户兑换价值与转点至航空公司的价值

不适用场景

  • 完成购买。 仅查找航班和酒店。请勿预订。
  • 非 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

两步验证流程

Amex 使用电子邮件 OTP 进行两步验证。首次登录时选择“Add This Device”后,同一配置文件后续运行将跳过两步验证。

工作原理: 触发两步验证时,脚本会向 stdout 输出 2FA_CODE_NEEDED,并向 stderr 输出 2FA REQUIRED,随后轮询验证码。最多等待 2 分钟。

对于 Agent: 当你在脚本输出中看到 2FA_CODE_NEEDED 时,请向用户索要 Amex 刚刚发送给他们的验证码。用户提供验证码后,将其写入验证码文件:

echo "123456" > /tmp/amex-2fa-code.txt

脚本会自动读取该文件并继续登录。

命令钩子(可选,用于完全自动化): 将 AMEX_2FA_COMMAND 设置为一个命令,该命令会阻塞运行直至获取验证码,然后将验证码输出到 stdout。脚本将运行此命令,而不是轮询文件。

首次登录时选择“Add This Device”后,同一配置文件的后续运行将跳过两步验证。

已知限制:travel-portal 登录验证码(2026 年 5 月)

截至 Amex 在 2026 年 5 月进行改版后,提交航班搜索会重定向到单独的 travel-portal 登录关卡(/account/travel/login)——即使已经登录 americanexpress.com 也一样——并受到基于风险的验证码层保护。脚本会自动填写并提交登录关卡,结果取决于 Amex 对该次会话的评分:

  • 有时可以通过——自动重新验证会被接受,搜索结果从头到尾正常加载(2026 年 7 月经实时验证:完整的 Docker 运行返回了 50 个已解析的航班)。
  • 有时会被静默拦截——提交后字段仍保留正确的值,表单自己的 #loginSubmit 已被点击,没有显示错误,DOM 中存在验证码标记,但页面始终不会继续跳转。同一天使用相同凭据和容器进行的实时验证也确认了这一点。

travel 会话的有效期也很短(next-auth 令牌,约 1 小时),因此热会话很快就会过期,登录关卡也会频繁重新出现。登录关卡失败时,脚本会打印一行 Gate diag:(字段/按钮/警报状态),以便通过日志诊断故障,随后立即退出,而不是一直等到搜索结果超时。酒店搜索也可能受到类似影响。

此登录关卡只会出现在新登录时。 如果有已保存的热会话(有效 Cookie + 可信设备),登录关卡会自动通过,搜索也能从头到尾正常运行。因此,恢复方法只需人工操作一次,并非无路可走:

  1. 如果登录关卡拒绝自动登录(无论是验证码或其他原因),脚本会向 stdout 打印 AMEX_HUMAN_LOGIN_NEEDED(并将 HUMAN_LOGIN_NEEDED 写入 /tmp/amex-2fa-status.txt)。**对于 Agent:**请停止重试,并告知用户运行刷新脚本。(另一个标记 AMEX_BAD_CREDENTIALS 表示凭据环境变量中包含尚未解析的密钥管理器引用,而非实际值——应修复凭据注入,而不是登录。)

  2. 用户在本地运行,而非在 Docker 中运行:

    python3 scripts/refresh_login.py
    

    系统会在 travel portal 中打开一个真正的 Chrome 窗口。用户自行登录(输入密码、完成验证码、输入邮件验证码、选择“添加此设备”),脚本会自动保存刷新后的 Cookie/配置文件,完成时打印 AMEX_SESSION_REFRESHED。

  3. 后续运行(包括挂载 ~/.amex-travel-profiles 的 Docker 运行)会复用热会话并跳过登录关卡。

为避免会话失效,每隔一两周运行一次简单搜索(或运行 refresh_login.py;它在检测到已登录页面后就会退出)。优先使用住宅 IP;数据中心和酒店 IP 会受到 Akamai 更严格的审查。

工作原理

航班搜索架构
  1. 身份验证: 从已保存的配置文件注入 Cookie。必要时会回退到新登录并通过邮件进行双重身份验证。
  2. 填写表单: 基于 DOM 的搜索表单自动化(机场自动补全、日历选择器、舱位选择器)
  3. 登录关卡: 提交表单后,Amex 会通过登录过渡页进行重定向。脚本会自动处理重新验证(取决于风险;请参阅“已知限制”)。
  4. 数据提取(新版 UI,2026 年 5 月及之后): 结果会加载到 travel.americanexpress.com/en-us/book/flights/search-results,这是一个无法从 window.appData 获取有用数据的 Next.js 应用(__NEXT_DATA__ 仅包含配置)。脚本会解析 DOM 中的 [data-testid="offer-card-wrapper"] 卡片,其中的航空公司、时间、机场、时长、中转次数、现金价格、积分价格以及原价/现价折扣均有专用的 data-testid。
  5. 数据提取(旧版回退方案): 如果没有出现报价卡片,脚本会回退到旧版的 window.appData Redux 存储提取方式(627KB JSON 数据块)。
  6. IAP 检测: 带有 private-fare-banner-PEP* 横幅且显示“原价 $X,现价 $Y”现金折扣的卡片属于 IAP(白金会员机票),通常是国际航班前舱票价的 10% 至 15% 折扣。Alaska“Insider Fares”(仅限积分折扣)会通过 insider_fare/points_discount 单独标记。
酒店搜索架构
  1. **填写表单:**与航班相同,采用基于 DOM 的方式
  2. **登录拦截页:**自动处理
  3. **数据提取:**酒店页面是一个 Next.js 应用,没有 window.appData。脚本使用 data-testid="hotel-offer-card" 元素解析 DOM。
  4. **FHR/THC 识别:**通过 data-testid="offer-banner" 文本(“Fine Hotels and Resorts” 或 “The Hotel Collection”)识别
  5. **礼遇提取:**FHR/THC 卡片通过 data-testid="offer-amenities-item" 元素显示礼遇(早餐、额度、升级)
数据结构

航班结果(来自 window.appData.flightSearch.itineraries[]):

  • pricing_information[],其中 fare_type = PEP(IAP)或 PUB(公开票价)
  • total_price.cents(现金),total_price_in_points(MR 点数,每点相当于 1 美分)
  • segment.legs[],包含承运航司、时间、时长、舱位、机型、设施
  • segment.seats_left、is_refundable、cancellation_policy

酒店结果(通过解析 DOM 获取):

  • 酒店名称、星级、城市、距离
  • TripAdvisor 评分和评论数
  • 每晚价格和总价
  • MR 点数成本
  • FHR/THC 会员资格及具体礼遇
  • 标准设施(Wi-Fi、早餐、停车)

国际航空计划(IAP)

白金卡礼遇。搭乘指定航空公司的国际航班时,可享受高端舱位优惠票价。显示为与 PUB(公开票价)并列的单独 PEP 票价类型。

  • 商务舱/头等舱通常可节省 10%–15%
  • 并非所有航线或航空公司都适用
  • 仅限使用白金卡登录后查看

输出格式

始终使用 Markdown 表格。

航班
#航空公司航线经停时长现金IAP 现金点数剩余座位
1TurkishSFO-IST-CDG120h 10m$5,044$4,381438,1133
酒店
#酒店计划星级每晚总价点数礼遇
1Hotel ContinentalFHR5$471$94294,200早餐、$100 额度、房型升级、延迟至 4pm 退房
表格之后
  • 标示 IAP 节省金额(显示折扣百分比)
  • 说明 FHR/THC 礼遇,以及这些礼遇如何抵扣房价
  • 计算 MR 兑换的实际 CPP(在 Amex 门户网站中,1 点 = 1 美分)
  • 与转点至航空公司的兑换价值进行比较
  • 说明白金卡每年 $600 的酒店额度(每半年 $300,FHR 和 THC 共享)

舱位代码

CLI 值Amex 代码描述
economyECONOMY标准经济舱
premiumPREMIUM_ECONOMY超级经济舱
businessBUSINESS商务舱
firstFIRST头等舱

环境变量

变量必需描述
AMEX_USERNAME是Amex 在线账户用户名
AMEX_PASSWORD是Amex 在线账户密码
AMEX_PROFILE否浏览器配置文件目录(默认:~/.amex-travel-profiles/default)
AMEX_2FA_COMMAND否在邮箱验证码就绪前阻塞并将其打印到标准输出的命令

故障排除

  • **搜索后出现登录拦截页:**这是正常情况。Amex 在提交表单后总会跳转至登录中间页。脚本会自动处理。
  • **未找到 appData(航班):**页面可能尚未完全加载。脚本会等待 Redux 存储填充。请检查是否已成功登录。
  • **酒店结果为空:**酒店数据通过解析 DOM 获取,而非 appData。如果 DOM 结构发生变化,可能需要更新 data-testid 选择器。
  • **日历选择器失效:**Amex 使用 div[role="button"] 表示日历日期(而非 <button>)。脚本使用类名模式 automation-date-picker-month-{year}-{month} 查找对应月份的容器。
  • **2FA 验证码被拒:**Amex 验证码过期很快。请确保使用的是新验证码(不是上次登录时的旧验证码)。

限制

  • 必须使用有头模式。 Amex 会检测无头模式。可通过 Docker+xvfb 绕过。
  • 每次搜索约需 45 秒。 登录 + 填写表单 + 登录验证 + 加载结果。
  • 酒店结果仅通过 DOM 获取。 酒店无法拦截 API(Next.js 应用的 __NEXT_DATA__ 为空)。解析器依赖 data-testid 属性。
  • 设备信任有帮助。 首次登录时选择“添加此设备”后,该配置文件可跳过 2FA。通过 Docker 卷挂载保持配置文件持久化。

评论

支持 Markdown