Day 39 - 综合项目1 - 低价航班查询 - Python学习笔记

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

Sheety API

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

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

Twilio Console

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)
相关推荐
伯明翰java5 小时前
Redis学习笔记-List列表(2)
redis·笔记·学习
云帆小二5 小时前
从开发语言出发如何选择学习考试系统
开发语言·学习
许泽宇的技术分享5 小时前
当AI学会“说人话“:Azure语音合成技术的魔法世界
后端·python·flask
光泽雨5 小时前
python学习基础
开发语言·数据库·python
Elias不吃糖5 小时前
总结我的小项目里现在用到的Redis
c++·redis·学习
BullSmall5 小时前
《道德经》第六十三章
学习
裤裤兔5 小时前
python爬取pdf文件并保存至本地
chrome·爬虫·python·pdf·网络爬虫
Solyn_HAN6 小时前
非编码 RNA(ceRNA/lncRNA/circRNA)分析完整流程:从数据下载到功能验证(含代码模板)
python·bash·生物信息学·r
CesareCheung6 小时前
JMeter 进行 WebSocket 接口压测
python·websocket·jmeter
beijingliushao6 小时前
95-Python爬虫-正则表达式
爬虫·python·正则表达式