关于 Flywizz
Flywizz 是用于获取 Wizz Air 航班数据的非官方开源 Python 封装,并附带 MCP 服务,可用自然语言搜索航班。它涵盖时刻表、票价、航线和航班状态,同时说明部分余票接口受机器人防护限制。
主要功能
- 01查询运营日期和时刻表
- 02按日期比较票价
- 03探索航线和目的地
- 04获取航班状态
- 05提供异步客户端方法
适用场景
- 01查找指定航线和日期范围的航班
- 02比较不同日期的票价
- 03探索从某机场出发的目的地
- 04查询航班状态
MCP 相关
内置 MCP 服务允许 MCP 客户端通过自然语言搜索 Wizz Air 航班。README 列出了 Claude Desktop、Claude Code 和 Cursor。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
5收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| adults | integer | 否 | |
| origin | string | 是 | |
| date_to | string | 是 | |
| infants | integer | 否 | |
| children | integer | 否 | |
| date_from | string | 是 | |
| destination | string | 是 | |
| wizz_discount_club | boolean | 否 |
详细介绍
Flywizz SDK
一个开源的非官方 API 封装,用于获取 Wizz Air 航班数据。
提示
内置面向 AI Agent 的 MCP 服务。 将 Flywizz 接入 Claude Desktop、 Claude Code 或 Cursor,即可用自然语言搜索 Wizz Air 航班。 跳转至 MCP 快速入门。
目录
- 安装
- 快速入门
- 首先需要了解的三件事
- API 参考
- 数据模型
- 示例
- 一次检查多条航线
- 需要中转的航班
- 探索模式
- 与 Claude、Cursor 和其他 MCP 客户端搭配使用
- API 特性
- 缓存
- 速率限制
- 参与贡献
- 免责声明
安装
pip install Flywizz
或使用 uv:
uv add Flywizz
快速入门
from datetime import datetime, timedelta
from flywizz import WizzAir, TimetableSearch
# Initialize the client
client = WizzAir()
# Set up search parameters
search = TimetableSearch(
origin="BUD", # Budapest
destination="LTN", # London Luton
date_from=datetime.now() + timedelta(days=30),
date_to=datetime.now() + timedelta(days=60),
)
# One call gets the schedule and the prices
for day in client.get_timetable(search):
if day.price is None:
continue
print(f"{day.departure_date.date()}: {day.price.amount} {day.price.currency}")
print(f" departures: {', '.join(d.departure.strftime('%H:%M') for d in day.departures)}")
每个条目对应一个运营日:当天最便宜的票价,以及当天所有的起飞时间,因此一次调用即可同时回答“何时有航班”和“价格是多少”。
首先需要了解的三件事
价格使用出发站的货币
Wizz Air 不支持在服务器端覆盖货币。BUD -> LTN 报价使用 HUF,
LTN -> BUD 报价使用 GBP,WAW -> LTN 报价使用 PLN。名为
currency 的请求体字段、查询参数、Cookie 和请求头都会被忽略。
如果你需要在搜索前了解将使用哪种货币,请从 get_network() 中读取
Station.currency_code,并在客户端进行换算。
并非每个运营日都有报价
timetableV2 和 farechart 会为每一天附加一个 price 对象,但对于
不会直接提供报价的日期,amount 为 0,而 price_type 为
checkPrice(存在票价,但只能通过 search/search 查询)或
noData。Flywizz 会将两者都映射为 price=None,因此无报价的日期绝不会被误认为免费。时刻表条目仍会通过
original_price 提供参考票价:
for day in client.get_timetable(search):
if day.price is not None:
print(day.departure_date.date(), day.price.amount, day.price.currency)
elif day.original_price is not None:
print(day.departure_date.date(), "~", day.original_price.amount, "(check price)")
搜索时间范围有限制,且上限各不相同
提供和不提供价格的接口对可查询的未来时间范围有不同限制。超出范围时,两者都会返回 400 InvalidTimeDateRange,且不提供进一步说明,因此 Flywizz 会自行执行各自的限制,并在提示消息中注明上限。
from flywizz.misc import (
MAX_TIMETABLE_WINDOW_DAYS, # 42, for timetableV2 and farechart
MAX_FLIGHT_DATES_WINDOW_DAYS, # 62, for the schedule endpoints
)
cheapest_weekend() 会在内部拆分时间范围,因为其默认值
months_ahead=3 远超任一上限。
search/search 受机器人防护机制限制
四个端点(search/search、booking/seatmap、booking/ancillaries、
booking/passengers)受 Kasada 防护,来自任何非浏览器客户端的请求都会返回空响应体和 429。Flywizz 会抛出 BotGateError,而不会尝试破解验证。
其他所有接口,包括可提供价格的 timetableV2 和 farechart,均开放访问。这足以用于价格跟踪、航线探索和日历搜索。如果你需要票价套餐和销售密钥,请通过真实浏览器会话发送请求,并传入会话的请求头:
from flywizz import WizzAir, WizzairTransport
client = WizzAir(WizzairTransport(kasada_headers={
"x-kpsdk-ct": "...",
"x-kpsdk-v": "...",
"x-kpsdk-h": "...",
"x-kpsdk-cd": "...",
}))
有关防护机制、会话握手以及完整航线表的详细信息,请参阅
docs/internal-api-spec.md。
API 参考
WizzAir 类
构造函数
WizzAir(transport: Optional[Transport] = None)
创建一个新的 Wizz Air 客户端实例。
参数:
transport(Transport,可选):注入自定义传输,例如包装默认传输的CachingTransport、带有kasada_headers的WizzairTransport,或用于测试的固定数据传输。默认使用全新的WizzairTransport。
示例:
# Defaults
client = WizzAir()
# With caching for the 650 KB network metadata
from flywizz import CachingTransport, WizzairTransport
client = WizzAir(CachingTransport(WizzairTransport(), ttl=3600))
方法
| 方法 | 端点 | 提供的内容 |
|---|---|---|
get_network(language="en-gb") | asset/map | 所有站点及其坐标、货币和连接信息 |
get_destinations(origin, direct_only=True) | 派生 | 从 origin 可到达的站点 |
explore_by_country(origin) | 派生 | 按国家/地区代码分组的目的地 |
validate_route(origin, destination) | 派生 | Wizz Air 是否运营这条直飞航线 |
get_flight_dates(origin, destination, date_from, date_to) | search/flightDates | 运营日期,不含价格,成本很低 |
get_flight_dates_multi(origin, destinations, date_from, date_to) | search/FlightDatesMultiArrival | 每次请求最多查询 5 个目的地的运营日期,分批处理 |
get_connecting_flight_dates(origin, destination, date_from, date_to) | search/dohopFlightDates | 包含一次中转的运营日期 |
get_timetable(params) | search/timetableV2 | 每天的最低票价及所有出发航班 |
get_return_timetable(params) | search/timetableV2 | 一次调用查询去程和回程 |
get_fare_chart(params) | asset/farechart | 目标日期前后的价格区间 |
get_availability(params) | search/search | 票价套餐和销售密钥。受机器人防护限制 |
cheapest_in_month(origin, destination, month) | 派生 | 一个日历月内最便宜的日期 |
cheapest_weekend(origin, destination, months_ahead=3) | 派生 | 最便宜的周五至周日或周五至周一往返行程 |
explore_with_fares(origin, date_from, date_to, limit=None) | 派生 | 所有目的地及其最低票价 |
get_flight_status(carrier_code, flight_number, date=None) | asset/flightinformation | 单个航班号的实时状态 |
get_currencies() | asset/currencies | 支持的 ISO 4217 代码 |
get_countries() | asset/country | 含欧盟 / 申根标记的国家/地区 |
get_cultures() | asset/cultures | 网站语言及其货币 |
get_service_fees(currencies=None) | asset/serviceFees | 已公布的行李、座位和改签费用 |
get_wdc_prices() | asset/wdcPrice | 折扣俱乐部等级和最低折扣 |
AsyncWizzAir 上也提供所有方法,且签名相同。
TimetableSearch 类
时刻表搜索的参数。
TimetableSearch(
origin: str,
destination: str,
date_from: datetime,
date_to: datetime,
return_date_from: Optional[datetime] = None,
return_date_to: Optional[datetime] = None,
adults: int = 1,
children: int = 0,
infants: int = 0,
price_type: str = "regular",
)
参数:
origin(str):出发站的 IATA 代码(例如"BUD")destination(str):到达站的 IATA 代码(例如"LTN")date_from(datetime):去程出发日期范围的起始时间date_to(datetime):去程出发日期范围的结束时间return_date_from/return_date_to(datetime,可选):回程日期范围。get_return_timetable()必须同时提供两者adults/children/infants(int):乘客人数。至少需要一名成人price_type(str):"regular"或"wdc",用于指定 Wizz Discount Club 价格
FareChartSearch 类
价格区间的参数。
FareChartSearch(
origin: str,
destination: str,
date: datetime,
day_interval: int = 3,
adults: int = 1,
children: int = 0,
infants: int = 0,
price_type: str = "regular",
)
day_interval 是 date 前后的半区间,且必须至少为 3,因此默认会返回七天的数据。较小的值会被上游拒绝,并返回
DayIntervalMustBeGreaterOrEqualTo3。
AvailabilitySearch 类
受机器人防护限制的可用性调用参数。
AvailabilitySearch(
origin: str,
destination: str,
departure_date: datetime,
return_date: Optional[datetime] = None,
wdc: bool = True,
is_flight_change: bool = False,
adults: int = 1,
children: int = 0,
infants: int = 0,
)
数据模型
Price
表示 Wizz Air 报告的金额。
属性:
amount(float):金额currency(str):ISO 4217 代码,始终为出发站的货币exchanged_amount(Optional[float]):SPA 的客户端转换钩子。 匿名会话中保持为Noneexchanged_currency(Optional[str]):exchanged_amount的货币
TimetableEntry
航线的一个运营日及其最低票价。
属性:
departure_station(str)、arrival_station(str):IATA 代码departure_date(datetime):运营日price(Optional[Price]):当天的最低票价;售罄时为Noneoriginal_price(Optional[Price]):折扣前价格departures(list[Departure]):当天的所有航班price_type(Optional[str]):有可售座位时为"price"has_mac_flight(bool):该航线包含都市区备选机场applied_coupon_code(Optional[str])
Departure
属性:
departure(datetime):出发时间is_cheapest_of_the_day(bool):该航班的price为当天最低价
FlightDate
get_connecting_flight_dates() 返回的一个运营日。
属性:
date(datetime):运营日stops(int):直飞为 0,中转为 1 或更高is_direct(bool):属性;当stops为 0 时为 true
FareChartEntry
价格条中的一天。
属性:
departure_station(str)、arrival_station(str):IATA 代码day(datetime):日期price(Optional[Price]):当天的最低价格class_of_service(Optional[str]):该报价所属的预订舱位price_type(Optional[str])、has_mac_flight(bool)
Station
Wizz Air 实时航线网络中的机场。由探索方法返回。
属性:
iata(str):IATA 机场代码name(str):机场名称country_code(str):大写 ISO2 国家代码(例如"HU"、"GB")country_name(str):国家名称currency_code(str):当地货币。此处出发的票价以该货币计价latitude(float)、longitude(float):坐标mac(Optional[str]):都市区代码(例如"LON")aliases(list[str]):别名categories(list[int]):Wizz Air 分配的营销类别rank(Optional[int)、is_fake_station(bool)connections(list[Connection]):该机场可飞往的所有地点
辅助方法:destinations(direct_only=True) 仅返回 IATA 代码。
Connection
属性:
iata(str):目的地机场代码is_direct(bool):Wizz Air 直飞航班。通常需要关注此标记is_connected(bool):自助中转,而非直飞航班is_domestic(bool)、is_new(bool)operation_start_date(Optional[datetime]):航线开通时间
FlightStatus
来自航班信息端点的一个运营航班。
属性:
flight_id(int)、carrier_code(str)、flight_number(int)departure_airport(str)、arrival_airport(str)original_departure_airport/original_arrival_airport(Optional[str]): 航班备降时,此处的机场与实际机场不同operation_day(Optional[datetime])scheduled_departure/scheduled_arrival(Optional[datetime])op_suffix(Optional[str])
DestinationFare
由 explore_with_fares() 返回。将可到达的目的地与其最低抽样票价配对;如果价格探测返回了票价,则包含该票价。
属性:
station(Station):目的地price(Optional[Price]):时间范围内的最低票价;如果该航线属于航线网络,但未返回有价座位,则为Nonedeparture_date(Optional[datetime]):该票价对应的日期
示例
一个月内价格最低的日期
from datetime import datetime
from flywizz import WizzAir
client = WizzAir()
cheapest = client.cheapest_in_month("BUD", "LTN", datetime(2026, 11, 1))
if cheapest:
print(f"{cheapest.departure_date.date()}: "
f"{cheapest.price.amount} {cheapest.price.currency}")
前后一天的票价是否更低?
from datetime import datetime
from flywizz import WizzAir, FareChartSearch
client = WizzAir()
strip = client.get_fare_chart(
FareChartSearch(origin="BUD", destination="LTN",
date=datetime(2026, 11, 10), day_interval=3)
)
for day in strip:
price = f"{day.price.amount:.0f} {day.price.currency}" if day.price else "-"
print(f"{day.day.date()} {price}")
未来三个月内票价最低的周末
from flywizz import WizzAir
client = WizzAir()
weekend = client.cheapest_weekend("BUD", "LTN", months_ahead=3)
if weekend:
out, back = weekend
total = out.price.amount + back.price.amount
print(f"{out.departure_date.date()} -> {back.departure_date.date()}: "
f"{total} {out.price.currency}")
Discount Club 票价
from datetime import datetime, timedelta
from flywizz import WizzAir, TimetableSearch
client = WizzAir()
wdc = client.get_timetable(
TimetableSearch(
origin="BUD", destination="LTN",
date_from=datetime.now() + timedelta(days=30),
date_to=datetime.now() + timedelta(days=45),
price_type="wdc",
)
)
实时航班状态
from flywizz import WizzAir
client = WizzAir()
for leg in client.get_flight_status("W6", "6201"):
print(f"{leg.operation_day.date()} {leg.departure_airport} -> {leg.arrival_airport}")
承运人代码为 AOC 前缀:W6(匈牙利)、W4(马耳他)、W9(英国)。
错误处理
from flywizz import BotGateError, ValidationError, WizzairException
try:
entries = client.get_timetable(search)
if not entries:
print("No flights found for the given criteria")
except ValidationError as e:
print(f"Wizz Air rejected the request: {e.codes}")
except BotGateError:
print("This endpoint needs a browser session")
except WizzairException as e:
print(f"Wizz Air API error: {e}")
ValidationError.codes 包含 Wizz Air 自己的验证代码,用于标识其认为有问题的字段。空列表表示 API 未返回任何匹配结果;这绝不表示发生了故障。
一次检查多条航线
get_flight_dates_multi() 可在每次请求中查询多个目的地的航班时刻,比循环调用
get_flight_dates() 便宜五倍:
from datetime import datetime, timedelta
from flywizz import WizzAir, WizzairTransport, CachingTransport
client = WizzAir(CachingTransport(WizzairTransport()))
start = datetime.now() + timedelta(days=30)
destinations = [s.iata for s in client.get_destinations("BUD")]
dates = client.get_flight_dates_multi("BUD", destinations, start, start + timedelta(days=30))
for iata, days in dates.items():
print(f"{iata}: {len(days)} operating days")
你查询的每个目的地都会出现在结果中。在指定时间范围内没有航班的航线会对应一个空列表,而不是直接缺失,因此无需担心忘记检查成员关系。
该端点每次请求最多查询五个目的地,若列表过长,会直接返回空结果而不是报错。Flywizz 会为你分批处理,因此传入列表没有实际数量限制。
票价则有所不同:目前没有批量查询票价的接口,因此 explore_with_fares() 仍需为每个目的地调用一次。
需要中转的航班
validate_route() 和 get_flight_dates() 仅覆盖直飞航班,因此任一方法返回 False,并不意味着你无法飞往该目的地。
get_connecting_flight_dates() 也会查询需要换乘飞机的航班:
from datetime import datetime, timedelta
from flywizz import WizzAir
client = WizzAir()
start = datetime.now() + timedelta(days=30)
client.validate_route("KTW", "LIS") # False - no direct flight
for day in client.get_connecting_flight_dates("KTW", "LIS", start, start + timedelta(days=30)):
print(day.date.date(), "direct" if day.is_direct else f"{day.stops} stop(s)")
如果一条航线只有部分日期有直飞航班,两种航班会交错返回,因此你可以查看哪些日期需要中转。只需要直飞航班时,可按 is_direct 进行筛选。
探索模式
探索模式回答“从这里实际可以飞到哪里?”这个问题。它会读取 Wizz Air 的实时航线网络元数据,并提供从任一机场可到达的目的地,还可按条件分组,或与指定日期范围内的最低票价合并。
以下所有方法均可用于 WizzAir 和 AsyncWizzAir。
列出所有目的地
for station in client.get_destinations("BUD"):
print(f"{station.iata} {station.name} ({station.country_code})")
传入 direct_only=False 可包含自行中转的航线。
对目的地分组
by_country = client.explore_by_country("BUD")
print(f"BUD flies to {len(by_country)} countries")
for country, stations in sorted(by_country.items()):
codes = ", ".join(s.iata for s in stations)
print(f" {country}: {codes}")
国家代码为大写 ISO2 代码。
检查单条航线
client.validate_route("BUD", "LTN") # True
查询目的地及其最低票价
explore_with_fares() 会将航线网络中的目的地与时刻表查询结果合并,因此每个目的地都会返回其最低 Price(如果该航线在指定日期范围内没有返回可售座位,则为 None)。
Wizz Air 没有“任意目的地”搜索,因此每个目的地都需要调用一次。遍历时使用 limit,并将传输层封装在 CachingTransport 中。
from datetime import datetime, timedelta
start = datetime.now() + timedelta(days=30)
end = start + timedelta(days=14)
results = client.explore_with_fares("BUD", start, end, limit=20)
priced = [d for d in results if d.price is not None]
for d in sorted(priced, key=lambda d: d.price.amount)[:10]:
print(f"{d.station.iata} {d.station.name}: "
f"{d.price.amount} {d.price.currency}")
所有目的地的票价都以出发地的货币表示,因此可以直接比较。
异步用法
AsyncWizzAir 提供了所有探索方法的对应版本,且 explore_with_fares() 会并发发起请求:
import asyncio
from datetime import datetime, timedelta
from flywizz import AsyncWizzAir
async def main():
async with AsyncWizzAir() as client:
results = await client.explore_with_fares(
"BUD",
datetime.now() + timedelta(days=30),
datetime.now() + timedelta(days=45),
limit=20,
concurrency=5,
)
print(f"{sum(1 for r in results if r.price)} priced destinations")
asyncio.run(main())
如果连续调用多个探索方法,请将传输层封装在 CachingTransport 中,以便只获取一次航线网络元数据并重复使用。
与 Claude、Cursor 及其他 MCP 客户端搭配使用
重要
只需运行两条命令即可完成:
uv tool install "Flywizz[mcp]" claude mcp add flywizz flywizz-mcp现在,你的 Agent 就能用自然语言搜索 Wizz Air 航班。无需 API 密钥,也无需账号。
Flywizz 提供可选的 Model Context Protocol 服务,让你的 Agent 能根据自然语言提示词搜索 Wizz Air 票价,例如 “11 月从布达佩斯飞往伦敦,哪天最便宜?” 或 “12 月第一周从布达佩斯可以飞到哪里?”。
快速入门
1. 安装带有 MCP 扩展的 Flywizz:
uv tool install "Flywizz[mcp]"
也可以使用 pip:
pipx install "Flywizz[mcp]"
这会在你的 PATH 中安装一个 flywizz-mcp 控制台脚本。
2. 将其添加到你的 Agent:
Claude Code(单行命令):
claude mcp add flywizz flywizz-mcp
Claude Desktop:在 macOS 上打开 ~/Library/Application Support/Claude/claude_desktop_config.json(或在 Windows 上打开 %APPDATA%\Claude\claude_desktop_config.json),并添加:
{
"mcpServers": {
"flywizz": {
"command": "flywizz-mcp"
}
}
}
然后重启 Claude Desktop。
Cursor:前往 Settings → MCP → Add new server,名称填写 flywizz,命令填写
flywizz-mcp。
3. 试着使用。 向你的 Agent 提问:
“11 月从布达佩斯飞往伦敦卢顿,哪天最便宜?”
Agent 应调用 cheapest_day,并传入 origin="BUD"、
destination="LTN"、month="2026-11-01",然后报告日期和票价。
货币
没有货币设置,因为 Wizz Air 没有此类设置。每个工具都会以出发站的当地货币返回价格,并同时报告货币代码。请告诉你的 Agent 报价时使用返回的货币,而不要默认使用欧元。
暴露的工具
该服务提供五个精选工具,方便 Agent 可靠地选择:
find_fares,适用于“11 月从 BUD 飞往 LTN 多少钱”这类问题,提供完整的逐日明细和每个出发时间cheapest_day,适用于“这个月从 X 飞往 Y,哪天最便宜”这类问题price_around,适用于“10 日前后一天的票价是否更便宜”这类问题explore_destinations,适用于“从 X 可以飞往哪些国家”这类问题flight_status,适用于“W6 6201 什么时候运营”这类问题
无需 API 密钥、账户或速率限制设置。该服务会在多次调用间复用单个缓存的 WizzAir 客户端,因此每个进程只会获取一次网络元数据。
有机器人验证门槛的 search/search 接口不会对外开放:它无法在无头进程中运行,而一个总是失败的 Agent 工具还不如没有。
API 特性
上游 API 的这些特性决定了此 SDK 能提供和不能提供的功能。Flywizz 会为你处理这些情况;了解它们有助于解释某些调用的行为。
| 行为 | |
|---|---|
| 国家代码 | 大写的 ISO 3166-1 alpha-2 代码。小写代码会被拒绝。 |
| 身份验证 | 匿名,但每个请求都需要进行会话握手,并使用会在调用之间轮换的 CSRF 令牌。 |
| 货币 | 由出发站决定,无法协商。请在客户端进行转换。 |
| 低价机票搜索 | 没有“任意目的地”接口。explore_with_fares() 会针对每个目的地分别发起一次调用。 |
| 可查询票价的接口 | timetableV2 和 farechart 是开放的;search/search 有访问门槛。 |
| 分页 | 无。每个响应都包含完整结果,因此 asset/map 有 650 KB。 |
| 时间窗口限制 | 时刻表窗口最多可跨越 42 天;班次计划窗口最多可跨越 62 天。 |
| 机器人防护 | Kasada 永久应用于四个端点。 |
缓存
asset/map 有 650 KB,且很少变更。如果你多次调用它,请对传输层进行包装:
from flywizz import WizzAir, WizzairTransport, CachingTransport
client = WizzAir(CachingTransport(WizzairTransport(), ttl=3600))
异步代码需要使用异步包装器。两者不可互换:混用时会引发 TypeError,而不是缓存协程。
from flywizz import AsyncWizzAir, AsyncWizzairTransport, AsyncCachingTransport
client = AsyncWizzAir(AsyncCachingTransport(AsyncWizzairTransport(), ttl=3600))
这两种包装器都不会缓存 POST 请求,因此票价始终是最新的。调用 invalidate() 可提前清除缓存。
速率限制
SDK 会通过指数退避机制重试网络错误和 5xx 响应,最多重试 4 次。它有意不会重试 429:在此 API 中,这表示 Kasada 机器人验证门槛,而不是服务过载;重试只会增加负载,仍然无法成功。
Wizz Air 的 API 无需身份验证,但它并不属于你。请文明使用:缓存网络元数据,适度控制 explore_with_fares() 的并行请求数量,不要在票价实际变化之前频繁查询。
贡献
这是一个开源项目。欢迎贡献 — 请参阅 CONTRIBUTING.md。面向 Agent 的架构说明见 AGENTS.md,关于上游 API 的所有已知信息均见 docs/internal-api-spec.md。
免责声明
这是一个非官方 API 封装,与 Wizz Air 没有关联。它只会向该航空公司官网使用的公开端点发送只读请求。使用风险自负,并请确保遵守 Wizz Air 的服务条款。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。