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)
相关推荐
databook33 分钟前
Pandas 与 Polars:语法、性能和资源占用方面的对比
python·数据分析·pandas
留岁35 分钟前
大模型推理部署 · 学习文档
学习
威哥爱编程39 分钟前
Python 智能体开发实战 10:本地跑得好好的,一并发就崩?把它做成一个能上线的服务
python·agent
威哥爱编程44 分钟前
Python 智能体开发实战 09:改了提示词,到底是变好还是变坏?搭一套能打分的离线评测
python·agent
meiying88381 小时前
多快递公司快递单号批量查询接口怎么对接?Python 聚合查询实现
java·大数据·python
小李不想当小白1 小时前
BKP备份寄存器与RTC实时时钟(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
Hello_Pyhx1 小时前
Deep-Live-Cam 源码配置思路:环境、模型与执行后端分开排查
python
张张123y2 小时前
后端第十六课:Multi-Agent 多智能体(让多个 Agent 分工协作)
大数据·数据库·人工智能·python·deepseek·dsh·agent 框架
全栈练习生2 小时前
大规模智能体仿真
python·ai
code2cat2 小时前
【随笔】vLLM前缀缓存:相同的开头怎样少算一次
人工智能·python·缓存·vllm