Day 039 - 항공권 가격 추적 프로젝트◎ Python/Udemy Python2024. 3. 8. 20:24
Table of Contents
반응형
로직
- 구글 시트에 가고 싶은 장소, 가격 상항선, 국가코드 저장
- API를 이용해 Flight Search에서 가격 찾기
- 상한선 아래면 그에 대한 데이터와 가격을 SMS로 전송
코드 전문
# main.py
from data_manager import DataManager
from flight_search import FlightSearch
from flight_data import FlightData
from notification_manager import NotificationManager
from datetime import datetime, timedelta
data = DataManager()
sheet_data = data.get_data()
# iataCode가 비어있을 시
for i in sheet_data:
if i['iataCode'] == '':
i['iataCode'] = FlightSearch.get_iatacode(city=i['city'])
data.update_data(sheet_data=sheet_data)
from_date = datetime.now() + timedelta(days = 1)
to_date = datetime.now() + timedelta(days = 180)
# 최저가 검색
for i in sheet_data:
# 최저가를 찾기 위해 데이터 입력
flight = FlightSearch.search_flight_price(
i['iataCode'],
from_date.strftime("%d/%m/%Y"),
to_date.strftime("%d/%m/%Y")
)
# 만약 설정한 최저가보다 가격이 낮다면 메세지 전송
if flight.price < i['lowestPrice']:
NotificationManager.send_message(
message=f"최저가가 발견되었습니다! {flight.from_city}-{flight.from_airport} 에서 {flight.to_city}-{flight.to_airport}로 가는 항공편이 ₩{flight.price}입니다. \n출발시각:{flight.out_date}\n도착시각{flight.return_date}"
)
# data_manager.py
from dotenv import load_dotenv
import os
import requests
from pprint import pprint
load_dotenv()
class DataManager:
def __init__(self) -> None:
self.endpoint = os.getenv('SHEETY_API_FLIGHT')
"""구글 시트 데이터 가져오기"""
def get_data(self):
r = requests.get(url=self.endpoint)
return r.json()['prices']
"""구글 시트에 IATA Code 업데이트"""
def update_data(self, sheet_data):
for city in sheet_data:
new_data = {
"price": {
"iataCode": city["iataCode"]
}
}
r = requests.put(
url=f"{self.endpoint}/{city['id']}",
json=new_data
)
# print(r.text)
# flight_search.py
from dotenv import load_dotenv
import os
import requests
from flight_data import FlightData
load_dotenv()
class FlightSearch:
# 알게된 점 : classmethod를 사용할 거면 cls를 사용해야 한다.
KEY = os.getenv("KIWI_API_KEY")
IATA_endpoint = "https://api.tequila.kiwi.com"
PRICE_endpoint = "https://tequila-api.kiwi.com/v2"
headers = {
"apikey": KEY
}
"""API에서 IATA Code 가져오기"""
@classmethod
def get_iatacode(cls, city):
local_endpoint = f"{cls.IATA_endpoint}/locations/query"
param = {
"term": city,
"location_types": "city",
}
r = requests.get(url=local_endpoint, params=param, headers=cls.headers)
res = r.json()['locations']
IATA_Code = res[0]['code']
return IATA_Code
"""최저가 항공권 검색"""
@classmethod
def search_flight_price(cls, IATA_Code, from_date, to_date):
local_endpoint = f"{cls.PRICE_endpoint}/search"
param = {
'fly_from': "ICN",
'fly_to': IATA_Code,
'date_from': from_date,
'date_to': to_date,
# 여기 아래 항목들 안넣으면 오류남
"nights_in_dst_from": 7,
"nights_in_dst_to": 28,
"one_for_city": 1,
"max_stopovers": 0,
'curr': "KRW",
}
r = requests.get(url=local_endpoint, params=param, headers=cls.headers)
# 인덱스 오류가 난다면 항공편 없음
try:
data = r.json()["data"][0]
except IndexError:
print(f"{IATA_Code}로 가는 항공편이 없습니다.")
return None
# 각 루트의 데이터를 저장 (메세지 보내기 위함)
flight_data = FlightData(
price=data["price"],
from_city=data["route"][0]["cityFrom"],
from_airport=data["route"][0]["flyFrom"],
to_city=data["route"][0]["cityTo"],
to_airport=data["route"][0]["flyTo"],
out_date=data["route"][0]["local_departure"].split("T")[0],
return_date=data["route"][1]["local_departure"].split("T")[0]
)
print(f"{flight_data.to_city}: ₩{flight_data.price}")
return flight_data
# flight_data.py
class FlightData:
def __init__(self, price, from_city, from_airport, to_city, to_airport, out_date, return_date):
self.price = price
self.from_city = from_city
self.from_airport = from_airport
self.to_city = to_city
self.to_airport = to_airport
self.out_date = out_date
self.return_date = return_date
# notification_manager.py
from twilio.rest import Client
import os
from dotenv import load_dotenv
import requests
load_dotenv()
class NotificationManager:
account_sid = os.getenv('ACCOUNT_SID')
auth_token = os.getenv('AUTH_TOKEN')
client = Client(account_sid, auth_token)
@classmethod
def send_message(cls, message):
message = cls.client.messages.create(
to=os.getenv("MY_PHONE_NUMBER"),
from_=os.getenv("MY_TO_NUMBER"),
body=message)
print(message.sid)
코드 별 설명
main.py
총체적인 명령 집합, 다양한 클래스들을 활용해서 객체를 실행하는 역할을 수행함
data_manager.py
구글 시트의 데이터를 불러오거나 업데이트하는 작업을 수행함. Sheety API
를 활용함.
flight_search.py
항공권의 가격 검색, 구글 시트의 IATA 코드 업데이트, SMS을 보내기 위한 FlightData를 만들기 위한 초석을 다짐.
search_flight_price
메소드에서 파라미터에 넣지 않으면 오류가 나는 항목들이 있음. 또한, JSON 파일을 해석하는 데에 어려움이 있었음.
date_from
: 귀국 항공편 날짜를 정하려면nights_in_dst_from
및nights_in_dst_to
파라미터가 추가로 필요합니다. (nights..
파라미터들은 최소/최대 체류 기간을 설정합니다.)one_for_city
:fly_to
로 가는 모든 항공편 중 최저가를 반환하도록 합니다.max_stoppvers
: 직항 항공편을 검색할지, 경유할지 선택합니다.
flight_data.py
SMS를 보내기 위한 항공권의 데이터를 담아두기 위한 클래스. 코드 가독성을 위해 만든 것 같음.
notification_manager.py
SMS를 보내기 위한 핵심 클래스.
느낀 점
API를 통해 받아온 JSON 파일을 해석하는 것이 생각보다 굉장히 어려운 일이라는 것을 깨닫게 되었습니다. 이전까지 했던 프로젝트들은 괜찮았지만 양이 굉장히 많아지니 어떤 값을 어떤 경로로 가져와야 하는 지에 대한 연습을 많이 해야된다는 것을 깨달았습니다.
부록
참고문헌
반응형
'◎ Python > Udemy Python' 카테고리의 다른 글
Day 040 - 항공권 가격 추적 프로젝트 (심화) (0) | 2024.03.08 |
---|---|
Day 038 - 구글 시트에 운동 기록 (1) | 2024.03.08 |
Day 037 - 습관 추적기 프로젝트 (0) | 2024.03.08 |
Day 036 - 주식시장 알림 프로젝트 (1) | 2024.03.08 |
Day 033 - API 활용 (1) | 2024.03.08 |
@Reo :: 코드 아카이브
자기계발 블로그