mcpField
S
southwest

southwest

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

关于 southwest

用于查询 Southwest 票价并监控现有预订降价的技能。它通过 Patchright 获取现金与积分价格、票价等级和潜在优惠,且不会更改预订。

主要功能

  1. 01查询现金和积分票价
  2. 02展示各票价等级价格
  3. 03监控预订价格下降
  4. 04只读检查改签价格
  5. 05通过 Docker 后台运行

适用场景

  1. 01比较 Southwest 现金与积分票价
  2. 02检查符合 Companion Pass 条件的票价
  3. 03查找已订航班的降价机会

安装

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

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

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

包含的文件

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

Dockerfile
scripts/
check_change.py
entrypoint.sh
monitor.py
search_fares.py

详细介绍

Southwest 航班搜索

通过 Patchright(一个可绕过检测的 Playwright 分支)搜索 southwest.com。Southwest 是唯一一家不接入任何 GDS、API 或航班搜索工具的美国主要航空公司。此技能是获取 Southwest 专属数据的唯一方式,包括票价等级、积分定价和 Companion Pass 资格。

需要 Patchright(一个可绕过检测的 Playwright 分支)。标准 Playwright 和 agent-browser 会被 SW 检测并拦截。Patchright 会修改浏览器指纹以绕过检测。

必须以有头模式运行(headless=False)。 即使使用 Patchright,SW 也能检测到无头浏览器。在 macOS 上,Chrome 窗口会短暂出现后关闭。若要在后台运行且不弹出窗口,请使用 Docker:

# Search new flights (default, no login needed)
docker run --rm ghcr.io/borski/sw-fares --origin SJC --dest DEN --depart 2026-05-15
docker run --rm ghcr.io/borski/sw-fares --origin SJC --dest DEN --depart 2026-05-15 --return 2026-05-18 --points --json

# Check existing reservation for price drops (requires SW login)
docker run --rm -e SW_USERNAME -e SW_PASSWORD \
  ghcr.io/borski/sw-fares change --conf ABC123 --first Jane --last Doe --json

# List all upcoming trips
docker run --rm -e SW_USERNAME -e SW_PASSWORD \
  ghcr.io/borski/sw-fares change --list --json

# Build locally
docker build -t sw-fares skills/southwest/

Docker 镜像使用 xvfb 在容器内创建虚拟显示器。Patchright 通过 xvfb 以“有头”模式运行,从而绕过 SW 的无头检测,且不会在你的机器上打开任何窗口。

# Install
pip install patchright && patchright install chromium

# Search cash fares
python3 scripts/search_fares.py --origin SJC --dest DEN --depart 2026-05-15

# Search cash + points
python3 scripts/search_fares.py --origin SJC --dest DEN --depart 2026-05-15 --return 2026-05-18 --points

# JSON output
python3 scripts/search_fares.py --origin SJC --dest DEN --depart 2026-05-15 --points --json

经过实践才总结出的关键实现细节:

  • 先导航到 southwest.com 首页,再导航到结果 URL。未经首页预热而直接访问 URL 会被拦截。
  • 使用 fareType=POINTS URL 参数查询积分定价。不要尝试点击页面上的积分切换按钮。
  • 每次运行都使用全新的持久化浏览器上下文(临时目录),避免指纹累积。
  • 从 [role='main'] 而不是 <main> 提取文本。<main> 元素包含预订表单;[role='main'] 包含航班结果。
  • 可通过按 # \d+ 模式拆分,并在 View seats 处结束,来解析航班区块。
  • 始终先关闭 Cookie 横幅。它会阻挡交互。

前置条件

pip install patchright && patchright install chromium

或者使用 Docker(无需本地安装):

# Pre-built image (fastest)
docker pull ghcr.io/borski/sw-fares:latest

# Or build locally
docker build -t sw-fares skills/southwest/

适用场景

  • 用户询问 Southwest 航班或票价
  • 需要查询积分定价(其他地方都无法获取)
  • 需要了解票价等级明细(Basic、Choice、Choice Preferred、Choice Extra)
  • 计算 Companion Pass 的价值
  • 比较 SW 积分、现金与其他航空公司的价格

不适用场景

  • 只需要 SW 的现金价格:改用 google-flights 技能(速度更快)
  • 完成购买:只查找航班,不要预订。
  • 非 Southwest 航空公司:使用 duffel、ignav、google-flights 或其他技能

Southwest 票价等级

票价积分现金Companion Pass改签/取消行李
Basic (Wanna Get Away)最低最低不符合仅可获抵用金免费 2 件
Choice (Wanna Get Away Plus)较低较低符合可转让抵用金免费 2 件
Choice Preferred (Anytime)较高较高符合可退款免费 2 件
Choice Extra (Business Select)最高最高符合可退款 + 优先服务免费 2 件

Companion Pass 的关键点: 只有 Choice 及以上等级符合资格。Basic 不符合。这会显著改变 CPP 的计算方式。

Companion Pass CPP 公式

启用 CP 时,一张机票可供两人出行:

Total cash value = qualifying_fare_cash x 2 passengers
CPP = total_cash_value / total_points x 100

始终表述为“积分为 2 人购买了价值 $X 的行程”。

搜索:使用脚本

不要尝试手动自动化 SW 预订表单。 表单很脆弱,其 React 状态也无法配合浏览器自动化。请改用脚本,它会直接导航到结果 URL。

# Local (opens a Chrome window briefly)
python3 skills/southwest/scripts/search_fares.py --origin SJC --dest DEN --depart 2026-05-15

# With return date and points
python3 skills/southwest/scripts/search_fares.py --origin SJC --dest DEN --depart 2026-05-15 --return 2026-05-18 --points

# JSON output for programmatic use
python3 skills/southwest/scripts/search_fares.py --origin SJC --dest DEN --depart 2026-05-15 --points --json

# Docker (no Chrome window, no display needed)
docker run --rm ghcr.io/borski/sw-fares --origin SJC --dest DEN --depart 2026-05-15 --return 2026-05-18 --points

脚本会处理所有步骤:首页预热、关闭 Cookie 横幅、提取结果以及切换积分模式。

脚本工作原理

  1. 以有头模式启动 Patchright(未检测到的 Playwright),并使用全新的浏览器配置文件
  2. 首先访问 southwest.com 首页,以建立正常的浏览会话
  3. 使用 fareType=USD 访问现金票价的结果 URL,或使用 fareType=POINTS 访问积分票价的结果 URL
  4. 等待 15 秒,让 SW 的 React 应用渲染航班数据
  5. 从 [role='main'] 提取航班文本(不是 <main>,后者是预订表单)
  6. 按 # \d+ 模式拆分航班文本块并进行解析
  7. 清理浏览器和临时配置文件

为什么使用 URL 中的 fareType,而不是点击 Points 切换项: 结果页上的 Points 标签与航班卡片处于不同的框架上下文。通过 Playwright 点击并不可靠。使用 URL 参数可以直接加载积分结果。加载两次页面(现金票价 + 积分票价)比加载一次再点击切换项更可靠。

为什么用 [role='main'] 而不是 main: SW 有两个内容区域。<main> HTML 元素包含预订表单。[role='main'] ARIA 属性标记的是航班结果。使用错误的区域会导致找不到任何航班。

输出格式

始终使用 Markdown 表格。 现金票价和积分票价分别放在不同的表格中。

现金票价
航班出发到达经停时长BasicChoiceCh PrefCh Extra
#1046:00AM9:35AM直飞2h 35m$277$317$387$432
#16817:40PM11:05PM直飞2h 25m$209$249$319$364
#481/37806:35AM12:05PM经 PHX 中转 1 次4h 30m$219$259$329$374
积分票价
航班出发到达经停时长BasicChoiceCh PrefCh Extra
#1046:00AM9:35AM直飞2h 35m23,500 +$5.6027,000 +$5.6033,000 +$5.6036,500 +$5.60
表格之后
  • 计算各票价等级的 CPP:cash_price / points x 100
  • 标明哪些票价符合 Companion Pass 资格(Choice 及以上)
  • 如果涉及 CP,显示 2 人出行的价值
  • 如果有其他航空公司的选项,则进行比较

故障排查

  • “No flights found”:SW 可能因自动请求过多而标记了该 IP。等待几分钟后重试,或尝试 Docker(网络栈不同)。
  • 弹出 Chrome 窗口:本地模式下属于预期行为。要避免弹窗,请使用 Docker。
  • 脚本卡住:SW 页面最多可能需要 20 秒才能渲染。通常等待 15 秒就足够,但网络较慢时可能需要更久。
  • 出现 “Oops” 错误页面:稍等片刻后重试。SW 网站有时不太稳定。

限制

  • 必须使用有头模式。 SW 会检测并阻止无头浏览器,即使使用 Patchright 的隐身补丁也一样。后台运行时可使用 Docker+xvfb 作为替代方案。
  • 没有代码共享数据。 SW 不与其他航空公司进行代码共享。
  • 每次搜索约需 20 秒。 包括预热首页和页面渲染时间。速度比 API 数据源慢。
  • 价格经常变动。 SW 使用动态定价。结果仅反映查询时的价格。
  • 单程搜索只会返回出发航班。 对于往返行程,脚本会获取去程票价。搜索返程航班票价需要额外加载一次 URL(未来增强功能)。

Change Flight 票价监控(check_change.py)

只读脚本。绝不会修改、更改或取消任何航班。

登录 southwest.com,查询已有预订,并读取 Change Flight 页面,检查票价是否已降至已支付价格以下。

Docker 用法(无弹窗)
# Set your SW credentials however you like (env vars, 1Password, etc.)
export SW_USERNAME="your_username"
export SW_PASSWORD="your_password"

# List all upcoming trips (auto-discover confirmation numbers)
docker run --rm -e SW_USERNAME -e SW_PASSWORD \
  ghcr.io/borski/sw-fares change --list --json

# Check a specific reservation for price drops
docker run --rm -e SW_USERNAME -e SW_PASSWORD \
  ghcr.io/borski/sw-fares change --conf ABC123 --first Jane --last Doe --json

# Local (opens Chrome window, for debugging only)
SW_USERNAME=your_user SW_PASSWORD=your_pass \
  python3 scripts/check_change.py --conf ABC123 --first Jane --last Doe --debug
重要提示:使用法定姓名

SW 预订使用预订记录上的法定姓名,而非昵称。请使用预订中显示的准确名字和姓氏。

工作原理
  1. 通过页眉登录弹出菜单登录 southwest.com
  2. 对于 --list:点击 My Account,展开每个行程的手风琴面板,提取确认号码
  3. 对于 --conf:导航到 Change Flight 页面,填写查询表单,选择两个航段,然后点击“查看选项”
  4. 读取更改结果页面,其中会显示所有可选航班的票价差额:
    • CURRENT FLIGHT = 你已预订的航班(Basic 单元格显示“CURRENT”,没有变化)
    • +2,000 = 此航班比你已支付的价格多 2,000 点
    • -2,000 = 此航班比你已支付的价格少 2,000 点(节省,可重新预订)
    • Unavail = 此票价舱位已售罄
  5. 将任何差额为负的航班标记为节省机会
安全防护措施
  1. DANGEROUS_LABELS 屏蔽列表:“更改此航班”、“确认”、“取消”、“预订”、“购买”等
  2. 在登录和查询阶段之后,每次点击按钮都会执行 is_dangerous_click() 检查
  3. extract_results() 仅供读取。在选择航段并点击“查看选项”之后,不会再执行任何点击操作
  4. 脚本会选择航段并查看备选项,但绝不会选择替代航班或确认任何更改
已验证可用的选择器(2026 年 4 月 5 日)

登录弹出菜单:

  • 触发器:button:has-text('Log in')
  • 用户名:input[aria-label*='Account']
  • 密码:input[name='password']
  • 提交:button[type='submit']:has-text('Log in')

更改航班查询表单:

  • 确认号码:input[id*='confirmationNumber']
  • 名字:input#passengerFirstName
  • 姓氏:input#passengerLastName
  • 提交:button#form-mixin--submit-button(文本:“继续”)

航段选择:

  • 复选框:label:has(input[type='checkbox'])(可见标签,隐藏输入框)
  • 继续:button#form-mixin--submit-button(文本:“查看选项”)
重要限制:关联的 Companion Pass 预订

change 命令不适用于关联 Companion Pass 的预订。SW 会显示横幅:“已关联同伴行程。若要更改,请先取消同伴的航班。”

对于关联 CP 的预订(或任何不希望登录的监控场景),请改用 monitor 子命令。它使用公开票价搜索流程,并将你已预订的航班号与当前搜索结果进行匹配。无需登录。

票价下降监控器(monitor.py)

将 SW 当前票价与已预订航班的已付金额进行比较。报告当前价格低于基准价的具体已预订航班(重新预订后可获得可收回的旅行抵用金)。

无需登录。 使用公开的票价搜索流程,并按航班号精确匹配。适用于更改航班流程受限的关联 CP 预订。

配置文件

提供一个 JSON 行程数组:

[
  {
    "name": "Trip name (display only)",
    "confirmation": "ABC123",
    "passenger": "Jane (free-text label, display only)",
    "outbound": {
      "origin": "SJC",
      "dest": "SAN",
      "date": "2026-04-30",
      "flight_number": "4107",
      "baseline_pts": 13000
    },
    "return": {
      "origin": "SAN",
      "dest": "SJC",
      "date": "2026-05-03",
      "flight_number": "4119",
      "baseline_pts": 17500
    }
  }
]

flight_number 必须与 SW 在搜索结果中的显示完全一致。对于多航段航班,其中会包含空格,例如 "3657 / 4630"。单程行程可省略 return 航段。

Docker 用法
# Check all trips in the config
docker run --rm -v /path/to/trips.json:/app/trips.json:ro \
  ghcr.io/borski/sw-fares monitor --config /app/trips.json

# Check just one trip by confirmation number
docker run --rm -v /path/to/trips.json:/app/trips.json:ro \
  ghcr.io/borski/sw-fares monitor --config /app/trips.json --only ABC123

# JSON output
docker run --rm -v /path/to/trips.json:/app/trips.json:ro \
  ghcr.io/borski/sw-fares monitor --config /app/trips.json --json
本地用法(短暂打开 Chrome 窗口)
python3 scripts/monitor.py --config /path/to/trips.json
工作原理
  1. 对配置中每个行程的每个航段:
    • 导航至 SW 首页(在不同航段之间重置 SPA 状态)
    • 使用 points fareType 搜索航线和日期
    • 验证结果 URL 包含指定的出发地和目的地(拒绝过期渲染结果)
    • 在结果中查找特定的已预订航班号
    • 读取该航班当前的 Basic 票价(点数)
    • 与配置中的 baseline_pts 进行比较
  2. 按航段报告节省金额(正数)或额外费用(负数),并给出行程总计
重新预订后

如果你重新预订某个航段以获得节省,请将配置中该航段的 baseline_pts 更新为新的(较低的)已付金额。否则,下次运行监控器时会继续错误地标记同一机会。

为何它优于变更流程
check_changemonitor
是否需要登录是否
是否适用于与 CP 关联的预订否是
是否始终显示备选方案是否(仅显示已预订的航班)
对 SW DOM 的脆弱依赖高(表单点击)低(URL 参数 + 文本解析)
输出详情所有备选方案的完整票价舱位差异你所预订航班的基础票价差异

monitor 是日常基线跟踪的合适工具。如果你想查看所有票价舱位的所有备选方案,check_change 很有用,但仅适用于非 CP 预订。

评论

支持 Markdown