Skip to content

Instantly share code, notes, and snippets.

@gaukas
Last active May 30, 2022 18:41
Show Gist options
  • Save gaukas/63eafba2efbc45283a370b7328c9e545 to your computer and use it in GitHub Desktop.
Save gaukas/63eafba2efbc45283a370b7328c9e545 to your computer and use it in GitHub Desktop.
Check United Airlines' Booking
#!/usr/bin/env python3
# Author: Gaukas <i@gauk.as>
# Date: 2022-05-29
# License: MIT
# This script mainly uses 2 API endpoints:
# - GET flight/upgradeListExtended (credits goes to uscardform: https://www.uscardforum.com/t/topic/82554)
# - POST flight/FetchFlights
# GET token/anonymous => x-authorization-api
# POST flight/FetchFlights (x-authorization-api) => []FlightInfo
# GET flight/upgradeListExtended (x-authorization-api, []FlightInfo) => Capacity/Authorized/Booked/Held for each cabin (Front/Middle/Rear) for each flight in []FlightInfo
import requests
import json
from time import sleep
from requests.structures import CaseInsensitiveDict
BASE_DOMAIN = "https://www.united.com/"
DEFAULT_FLIGHT_NBR = 857
DEFAULT_FLIGHT_DATE = "2022-12-16"
DEFAULT_FROM_AIRPORT = "SFO"
DEFAULT_TO_AIRPORT = "PVG"
BOOKING_CLASSES = {
"ECONOMY": ["Y", "B", "M", "E", "U", "H", "Q", "V", "W", "S", "T", "L", "K", "G"],
"ECO-PREMIUM": ["O", "A", "R"],
"MIN-BUSINESS-OR-FIRST": ["J", "C", "D", "Z", "P", "I"]
}
req_url = ""
req_headers = CaseInsensitiveDict()
def set_initial_headers():
req_headers["accept"] = "*/*"
req_headers["user-agent"] = "insomnia/2022.3.0"
req_headers["accept-language"] = "en-US"
def set_x_authorization_api():
set_initial_headers()
if "x-authorization-api" not in req_headers:
req_headers["x-authorization-api"] = "bearer "+_get_token_anonymous()
def list_flights(Origin: str = DEFAULT_FROM_AIRPORT, Destination: str = DEFAULT_TO_AIRPORT, DepartDate: str = DEFAULT_FLIGHT_DATE, CabinPreferenceMain: str = "economy", StopCountMin: int = -1, StopCountMax: int = 0):
return _post_flight_fetchflights(Origin, Destination, DepartDate, CabinPreferenceMain, StopCountMin, StopCountMax)
def list_cabin_booking(flightNumber: int = DEFAULT_FLIGHT_NBR, flightDate: str = DEFAULT_FLIGHT_DATE, fromAirportCode: str = DEFAULT_FROM_AIRPORT):
return _get_flight_upgradelistextended(flightNumber, flightDate, fromAirportCode)
# Internal helper functions. These functions assume that all necessary headers are set and will fail if they are actually not.
def _get_token_anonymous():
req_url = BASE_DOMAIN+"api/token/anonymous"
resp = requests.get(req_url, headers=req_headers, timeout=20)
resp_json = resp.json()
if "data" in resp_json:
if "token" in resp_json["data"]:
if "hash" in resp_json["data"]["token"]:
return resp_json["data"]["token"]["hash"]
else:
raise NameError('data.token.hash not found in response')
def _post_flight_fetchflights(Origin: str, Destination: str, DepartDate: str, CabinPreferenceMain: str, StopCountMin: int = -1, StopCountMax: int = 0): # Content-Type: application/json, Accept-Language: en-US, x-authorization-api: {token}
req_url = BASE_DOMAIN+"api/flight/FetchFlights"
# Inject _body_FetchFlights for fields
_body_FetchFlights["Trips"][0]["Origin"] = Origin
_body_FetchFlights["Trips"][0]["Destination"] = Destination
_body_FetchFlights["Trips"][0]["DepartDate"] = DepartDate
_body_FetchFlights["Trips"][0]["SearchFiltersIn"]["StopCountMin"] = StopCountMin
_body_FetchFlights["Trips"][0]["SearchFiltersIn"]["StopCountMax"] = StopCountMax
_body_FetchFlights["CabinPreferenceMain"] = CabinPreferenceMain
flights = []
req_headers["content-type"] = "application/json"
req = requests.Request('POST',req_url,headers=req_headers,data=json.dumps(_body_FetchFlights))
prepared = req.prepare()
s = requests.Session()
sleep(1)
resp = s.send(prepared, timeout=20)
resp_json = resp.json()
if "data" in resp_json:
if "Trips" in resp_json["data"]:
for trip in resp_json["data"]["Trips"]:
if "Flights" in trip:
for flight in trip["Flights"]:
flight_info = {
"Origin": flight["Origin"],
"DepartDateTime": flight["DepartDateTime"],
"Destination": flight["Destination"],
"DestinationDateTime": flight["DestinationDateTime"],
"BookingClassAvailability": flight["BookingClassAvailability"],
"Carrier": flight["MarketingCarrier"],
"FlightNumber": flight["FlightNumber"],
"Cabins": []
}
for cabin in flight["Products"]:
if 'Description' not in cabin:
continue
cabin_info = {
"Description": cabin['Description'],
"Code": cabin['BookingCode']
}
for price in cabin["Prices"]:
if price["PricingType"] == "Fare":
cabin_info["Fare"] = price["Amount"]
flight_info["Cabins"].append(cabin_info)
if "EquipmentDisclosures" in flight:
flight_info["EquipmentDescription"] = flight["EquipmentDisclosures"]["EquipmentDescription"]
flights.append(flight_info)
else:
raise NameError('data.Trips not found in response')
return flights
def _get_flight_upgradelistextended(flightNumber: int, flightDate: str, fromAirportCode: str):# Accept-Language: en-US, x-authorization-api: {token}
req_url = BASE_DOMAIN+"api/flight/upgradeListExtended"
req_params = {
"flightNumber": flightNumber,
"flightDate": flightDate,
"fromAirportCode": fromAirportCode
}
resp = requests.get(req_url, headers=req_headers, params=req_params, timeout=20)
pbts_export = CaseInsensitiveDict()
resp_json = resp.json()
if "pbts" in resp_json and len(resp_json["pbts"]) > 0:
for pbt in resp_json["pbts"]:
if "cabin" in pbt and "capacity" in pbt and "authorized" in pbt and "booked" in pbt and "held" in pbt:
pbt_export = {}
pbt_export["capacity"] = pbt["capacity"]
pbt_export["authorized"] = pbt["authorized"]
pbt_export["booked"] = pbt["booked"]
pbt_export["held"] = pbt["held"]
pbts_export[pbt["cabin"]] = pbt_export
return pbts_export
_body_FetchFlights = {
"SearchTypeSelection": 1,
"SortType": "bestmatches",
"SortTypeDescending": False,
"Trips": [
{
"Origin": "SFO",
"Destination": "PVG",
"DepartDate": "2022-11-01",
"Index": 1,
"TripIndex": 1,
"SearchRadiusMilesOrigin": "-1",
"SearchRadiusMilesDestination": "-1",
"DepartTimeApprox": 0,
"SearchFiltersIn": {
"FareFamily": "ECONOMY",
"AirportsStop": None,
"AirportsStopToAvoid": None,
"StopCountMax": 0,
"StopCountMin": -1
},
"UseFilters": True,
"NonStopMarket": True
}
],
"CabinPreferenceMain": "economy",
"PaxInfoList": [
{
"PaxType": 1
}
],
"AwardTravel": False,
"NGRP": False,
"CalendarLengthOfStay": 0,
"PetCount": 0,
"CalendarFilters": {
"Filters": {
"PriceScheduleOptions": {
"Stops": 1
}
}
},
"Characteristics": [
{
"Code": "SOFT_LOGGED_IN",
"Value": False
},
{
"Code": "UsePassedCartId",
"Value": False
}
],
"FareType": "Refundable"
}
if __name__ == "__main__":
set_initial_headers()
set_x_authorization_api()
origin_airport = DEFAULT_FROM_AIRPORT
destination_airport = DEFAULT_TO_AIRPORT
flight_date = DEFAULT_FLIGHT_DATE
# First, list every available flight from DEFAULT_FROM_AIRPORT to DEFAULT_TO_AIRPORT on DEFAULT_FLIGHT_DATE.
# Here for example we list only direct flights (no connections)
flights = list_flights(Origin=origin_airport, Destination=destination_airport, DepartDate=flight_date)
if len(flights) == 0:
print("No flights found")
exit(1)
else:
print("Found {} flights from {} to {} on {}".format(len(flights), origin_airport, destination_airport, flight_date))
print("")
for flight in flights:
# For each of these flights: print the flight number, the departure date and time, the destination airport code and the cabin availability.
print(f"{flight['Carrier']}{flight['FlightNumber']} - {flight['EquipmentDescription']}")
# Get the cabin booking information for each of these flights.
cabin_booking = list_cabin_booking(flightNumber=flight["FlightNumber"], flightDate=flight_date, fromAirportCode=origin_airport)
if len(cabin_booking) == 0:
print("No cabin booking information available yet.")
else:
print("Cabin: Capacity/Authorized/Booked/Held")
for cabin in cabin_booking:
print(f"{cabin}: {cabin_booking[cabin]['capacity']}/{cabin_booking[cabin]['authorized']}/{cabin_booking[cabin]['booked']}/{cabin_booking[cabin]['held']}")
for cabin in flight['Cabins']:
print(f"{cabin['Description']}({cabin['Code']}): ${cabin['Fare']}")
print(f"{flight['BookingClassAvailability']}")
print("=======================================")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment