Udemy - 100 Days of Code: The Complete Python Pro Bootcamp
Day 39 - Intermediate+ - CAPSTONE Part 1 - Cheap Flight Finder
目录
-
-
-
- [294. Step 1 - Project Overview](#294. Step 1 - Project Overview)
- [295. Step 2 - Read and Write Google Sheet](#295. Step 2 - Read and Write Google Sheet)
- [296. Step 3 - Get the IATA Codes](#296. Step 3 - Get the IATA Codes)
- [297. Step 4 - Search for Cheap Flights](#297. Step 4 - Search for Cheap Flights)
- [298. Step 5 - Send Messages](#298. Step 5 - Send Messages)
- [299. Complete Project](#299. Complete Project)
-
-

294. Step 1 - Project Overview

295. Step 2 - Read and Write Google Sheet
python
import requests
import os
from dotenv import load_dotenv
load_dotenv()
class DataManager:
def __init__(self):
self.prices_endpoint = os.environ["SHEETY_PRICES_ENDPOINT"]
self.destination_data = {}
def get_destination_data(self):
response = requests.get(self.prices_endpoint)
data = response.json()
self.destination_data = data["prices"]
return self.destination_data
def update_destination_codes(self, data):
for city in data:
new_data = {
"price": {
"iataCode": city["iataCode"]
}
}
response = requests.put(f"{self.prices_endpoint}/{city['id']}", json=new_data)
print(response.text)
class FlightSearch:
def get_destination_code(self, city_name):
code = "TESTING"
return code
# Set up the Flight Search
data_manager = DataManager()
flight_search = FlightSearch()
# Update the IATA Codes in Google Sheet
sheet_data = data_manager.get_destination_data()
for row in sheet_data:
if row["iataCode"] == "":
row["iataCode"] = flight_search.get_destination_code(row["city"])
data_manager.update_destination_codes(sheet_data)
296. Step 3 - Get the IATA Codes
Amadeus API - Authorization
Amadeus API - City Search
python
class FlightSearch:
def __init__(self):
self._api_key = os.environ["AMADEUS_API_KEY"]
self._api_secret = os.environ["AMADEUS_API_SECRET"]
self._token = self._get_new_token()
def _get_new_token(self):
token_endpoint = "https://test.api.amadeus.com/v1/security/oauth2/token"
data = {
"grant_type": "client_credentials",
"client_id": self._api_key,
"client_secret": self._api_secret
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(token_endpoint, data=data, headers=headers)
print(f"Your token is {response.json()['access_token']}")
print(f"Your token expires in {response.json()['expires_in']} seconds")
return response.json()["access_token"]
def get_destination_code(self, city_name):
iata_endpoint = "https://test.api.amadeus.com/v1/reference-data/locations/cities"
params = {
"keyword": city_name,
"max": "2",
"include": "AIRPORTS",
}
headers = {"Authorization": f"Bearer {self._token}"}
response = requests.get(iata_endpoint, params=params, headers=headers)
try:
code = response.json()["data"][0]["iataCode"]
except (IndexError, KeyError):
print(f"No airport code found for {city_name}.")
return "N/A"
return code
297. Step 4 - Search for Cheap Flights
Amadeus API - Flight Offers Search
python
from datetime import datetime, timedelta
class FlightSearch:
...
def check_flights(self, orig_city_code, dest_city_code, start_date, search_days):
all_flights = []
for offset in range(0, search_days, 7):
flight_endpoint = "https://test.api.amadeus.com/v2/shopping/flight-offers"
params = {
"originLocationCode": orig_city_code,
"destinationLocationCode": dest_city_code,
"departureDate": (start_date + timedelta(days=offset)).strftime("%Y-%m-%d"),
"returnDate": (start_date + timedelta(days=offset + 7)).strftime("%Y-%m-%d"),
"adults": 1,
"nonStop": "true",
"currencyCode": "GBP",
"max": "10",
}
headers = {"Authorization": f"Bearer {self._token}"}
response = requests.get(flight_endpoint, params=params, headers=headers)
all_flights.extend(response.json().get("data", []))
return all_flights
class FlightData:
def __init__(self, price, orig_airport, dest_airport, out_date, return_date):
self.price = price
self.orig_airport = orig_airport
self.dest_airport = dest_airport
self.out_date = out_date
self.return_date = return_date
def find_cheapest_flight(data):
if not data:
return FlightData("N/A", "N/A", "N/A", "N/A", "N/A")
first_flight = data[0]
lowest_price = float(first_flight["price"]["grandTotal"])
cheapest_flight = first_flight
for flight in data:
price = float(flight["price"]["grandTotal"])
if price < lowest_price:
lowest_price = price
cheapest_flight = flight
orig_airport = cheapest_flight["itineraries"][0]["segments"][0]["departure"]["iataCode"]
dest_airport = cheapest_flight["itineraries"][0]["segments"][0]["arrival"]["iataCode"]
out_date = cheapest_flight["itineraries"][0]["segments"][0]["departure"]["at"].split("T")[0]
return_date = cheapest_flight["itineraries"][1]["segments"][0]["departure"]["at"].split("T")[0]
return FlightData(lowest_price, orig_airport, dest_airport, out_date, return_date)
# Search for Cheap Flights
origin = "LON"
tomorrow = datetime.now() + timedelta(days=1)
duration = 6 * 30
for destination in sheet_data:
print(f"\nGetting flights for {destination['city']}...")
flights = flight_search.check_flights(origin, destination["iataCode"], tomorrow, duration)
flight_data = find_cheapest_flight(flights)
print(f"{destination['city']}: £{flight_data.price}")
298. Step 5 - Send Messages
python
from twilio.rest import Client
class NotificationManager:
def __init__(self):
self.account_sid = os.environ["TWILIO_ACCOUNT_SID"]
self.auth_token = os.environ["TWILIO_AUTH_TOKEN"]
def send_message(self, message_body):
client = Client(self.account_sid, self.auth_token)
client.messages.create(
body=message_body,
from_=os.environ["TWILIO_VIRTUAL_NUMBER"],
to=os.environ["TWILIO_VERIFIED_NUMBER"]
)
# Send Notifications
if flight_data.price != "N/A" and flight_data.price < destination["lowestPrice"]:
print(f"Lower price flight found to {destination['city']}!")
message = (
f"Low Price Alert! Only £{flight_data.price} to fly! \n"
f"【Route】{flight_data.orig_airport} -- {flight_data.dest_airport} \n"
f"【Dates】{flight_data.out_date} -- {flight_data.return_date}"
)
notification_manager.send_message(message_body=message)
299. Complete Project
bash
SHEETY_PRICES_ENDPOINT="https://api.sheety.co/**********/flightDeals/prices"
AMADEUS_API_KEY="**********"
AMADEUS_API_SECRET="**********"
TWILIO_ACCOUNT_SID="**********"
TWILIO_AUTH_TOKEN="**********"
TWILIO_VIRTUAL_NUMBER="whatsapp:+1**********"
TWILIO_VERIFIED_NUMBER="whatsapp:+1**********"
python
import requests
from datetime import datetime, timedelta
import os
from dotenv import load_dotenv
from twilio.rest import Client
load_dotenv()
class DataManager:
def __init__(self):
self.prices_endpoint = os.environ["SHEETY_PRICES_ENDPOINT"]
self.destination_data = {}
def get_destination_data(self):
response = requests.get(self.prices_endpoint)
data = response.json()
self.destination_data = data["prices"]
return self.destination_data
def update_destination_codes(self, data):
for city in data:
new_data = {
"price": {
"iataCode": city["iataCode"]
}
}
response = requests.put(f"{self.prices_endpoint}/{city['id']}", json=new_data)
print(response.text)
class FlightSearch:
def __init__(self):
self._api_key = os.environ["AMADEUS_API_KEY"]
self._api_secret = os.environ["AMADEUS_API_SECRET"]
self._token = self._get_new_token()
def _get_new_token(self):
token_endpoint = "https://test.api.amadeus.com/v1/security/oauth2/token"
data = {
"grant_type": "client_credentials",
"client_id": self._api_key,
"client_secret": self._api_secret
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(token_endpoint, data=data, headers=headers)
print(f"Your token is {response.json()['access_token']}")
print(f"Your token expires in {response.json()['expires_in']} seconds")
return response.json()["access_token"]
def get_destination_code(self, city_name):
iata_endpoint = "https://test.api.amadeus.com/v1/reference-data/locations/cities"
params = {
"keyword": city_name,
"max": "2",
"include": "AIRPORTS",
}
headers = {"Authorization": f"Bearer {self._token}"}
response = requests.get(iata_endpoint, params=params, headers=headers)
try:
code = response.json()["data"][0]["iataCode"]
except (IndexError, KeyError):
print(f"No airport code found for {city_name}.")
return "N/A"
return code
def check_flights(self, orig_city_code, dest_city_code, start_date, search_days):
all_flights = []
for offset in range(0, search_days, 7):
flight_endpoint = "https://test.api.amadeus.com/v2/shopping/flight-offers"
params = {
"originLocationCode": orig_city_code,
"destinationLocationCode": dest_city_code,
"departureDate": (start_date + timedelta(days=offset)).strftime("%Y-%m-%d"),
"returnDate": (start_date + timedelta(days=offset + 7)).strftime("%Y-%m-%d"),
"adults": 1,
"nonStop": "true",
"currencyCode": "GBP",
"max": "10",
}
headers = {"Authorization": f"Bearer {self._token}"}
response = requests.get(flight_endpoint, params=params, headers=headers)
all_flights.extend(response.json().get("data", []))
return all_flights
class FlightData:
def __init__(self, price, orig_airport, dest_airport, out_date, return_date):
self.price = price
self.orig_airport = orig_airport
self.dest_airport = dest_airport
self.out_date = out_date
self.return_date = return_date
def find_cheapest_flight(data):
if not data:
return FlightData("N/A", "N/A", "N/A", "N/A", "N/A")
first_flight = data[0]
lowest_price = float(first_flight["price"]["grandTotal"])
cheapest_flight = first_flight
for flight in data:
price = float(flight["price"]["grandTotal"])
if price < lowest_price:
lowest_price = price
cheapest_flight = flight
orig_airport = cheapest_flight["itineraries"][0]["segments"][0]["departure"]["iataCode"]
dest_airport = cheapest_flight["itineraries"][0]["segments"][0]["arrival"]["iataCode"]
out_date = cheapest_flight["itineraries"][0]["segments"][0]["departure"]["at"].split("T")[0]
return_date = cheapest_flight["itineraries"][1]["segments"][0]["departure"]["at"].split("T")[0]
return FlightData(lowest_price, orig_airport, dest_airport, out_date, return_date)
class NotificationManager:
def __init__(self):
self.account_sid = os.environ["TWILIO_ACCOUNT_SID"]
self.auth_token = os.environ["TWILIO_AUTH_TOKEN"]
def send_message(self, message_body):
client = Client(self.account_sid, self.auth_token)
client.messages.create(
body=message_body,
from_=os.environ["TWILIO_VIRTUAL_NUMBER"],
to=os.environ["TWILIO_VERIFIED_NUMBER"]
)
# Set up the Flight Search
data_manager = DataManager()
flight_search = FlightSearch()
notification_manager = NotificationManager()
# Update the Airport Codes in Google Sheet
sheet_data = data_manager.get_destination_data()
for row in sheet_data:
if row["iataCode"] == "":
row["iataCode"] = flight_search.get_destination_code(row["city"])
data_manager.update_destination_codes(sheet_data)
# Search for Cheap Flights
origin = "LON"
tomorrow = datetime.now() + timedelta(days=1)
duration = 6 * 30
for destination in sheet_data:
print(f"\nGetting flights for {destination['city']}...")
flights = flight_search.check_flights(origin, destination["iataCode"], tomorrow, duration)
flight_data = find_cheapest_flight(flights)
print(f"{destination['city']}: £{flight_data.price}")
# Send Notifications
if flight_data.price != "N/A" and flight_data.price < destination["lowestPrice"]:
print(f"Lower price flight found to {destination['city']}!")
message = (
f"Low Price Alert! Only £{flight_data.price} to fly! \n"
f"【Route】{flight_data.orig_airport} -- {flight_data.dest_airport} \n"
f"【Dates】{flight_data.out_date} -- {flight_data.return_date}"
)
notification_manager.send_message(message_body=message)