Day 39 - Intermediate+ Capstone Part 1: Flight Deal Finder

本章由 Shadow 分享,筆記連結網址於此,由 Sky 取得同意後,整理如下。

時間:2021年6月6日 20:00~20:30
與會人員:Shadow, 玉米, Dot, Wayne, Yeh, Sky
分享:Shadow

目標

Flight Deal Feal

每日傳送最低機票票價資訊,地點及時間取至使用者自行設置的 Google Sheet 資訊,最後將最低機票票價資訊以 Line Notify 通知使用者

參考資料

Sheety

RapidAPI

Skyscanner API

https://skyscanner.github.io/slate/#browse-quotes

LINE Notify

說明文件:

流程及步驟

step 1:建立一個Google sheet表單,可參考下圖:

step 2:到Sheety中連結Google Sheet

import requests
SHEET_USERNAME="your SHEET_USERNAME"
PROJECTNAME="your PROJECTNAME"
SHEETNAME="your SHEETNAME"

SHEETYURL=f'https://api.sheety.co/{SHEET_USERNAME}/{PROJECTNAME}/{SHEETNAME}'

def getShrrtyYUrl(SHEET_USERNAME,PROJECTNAME,SHEETNAME):
	return f'https://api.sheety.co/{SHEET_USERNAME}/{PROJECTNAME}/{SHEETNAME}'

def getFlightInformation(sheetyUrl=SHEETYURL):
	getInformation = requests.get(sheetyUrl)
	return getInformation.json()

def insertInformation( country, currency, locale, originPlace, destinationPlace, outboundPartialDate, inboundPartialDate='',sheetyUrl=SHEETYURL):
	if not country and currency and locale and originPlace and destinationPlace and outboundPartialDate:
		print('Please input required data')
		return False

	parameters ={
		SHEETNAME:{
			 "country":country,
			 "currency":currency,
			 "locale":locale,
			 "originPlace":originPlace,
			 "destinationPlace":destinationPlace,
			 "outboundPartialDate":outboundPartialDate,
			 "inboundPartialDate":inboundPartialDate,
			}
		}
	try:
		response = requests.post(sheetyUrl, json=parameters)
		return True
	except  Exception  as err:
		print('insert error:', err)
		return False

def updateInformation(objectID,sheetyUrl=SHEETYURL, **updatedata,):
	updateUrl=sheetyUrl+'/'+str(objectID)
	headers={"Content-Type" : "application/json"}
	parameters={
		SHEETNAME:
			updatedata

	}
	try:
		updateRes=requests.put(updateUrl, json=parameters, headers=headers)
		updateRes.raise_for_status()
		return True
	except  Exception  as err:
		print('update error:',err)
		return False

step 3:搜尋航班

Skyscanner Flight Search

import requests

APIENDPOINT='https://partners.api.skyscanner.net/apiservices/'
APIKEY ='your apikey' #input your apikey

def getLocales(apiKey=APIKEY):
	locales_url=f'{APIENDPOINT}/reference/v1.0/locales?apiKey={apiKey}'
	locales_res=requests.get(locales_url)
	return locales_res.json()

def getCurrency(apiKey=APIKEY):
	currency_url=f"{APIENDPOINT}/reference/v1.0/currencies?apiKey={apiKey}"
	currency_res=requests.get(currency_url)
	return currency_res.json()

def getMarkent(locate,apiKey=APIKEY):
	market_url= f"{APIENDPOINT}/reference/v1.0/countries/{locate}?apiKey={apiKey}"
	market_res=requests.get(market_url)
	return market_res.json()

def getPlace(country,currency,locate,query,apiKey=APIKEY):
	place_url=f"{APIENDPOINT}/autosuggest/v1.0/{country}/{currency}/{locate}?query={query}&apiKey={apiKey}"
	place_res=requests.get(place_url)
	return place_res.json()

def getCheapestQuotes(country,currency,locale,originPlace,destinationPlace,outboundPartialDate,inboundPartialDate):
	cheapFlightUrl = f"https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/browsequotes/v1.0/" \
					 f"{country}/{currency}/{locale}/{originPlace}/{destinationPlace}/{outboundPartialDate}/{inboundPartialDate}"

	headers = {
		'x-rapidapi-key': "your rapidapi key",
		'x-rapidapi-host': "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com"
	}

	response = requests.get(cheapFlightUrl, headers=headers)
	return response.json()

step 4:Line Notify 通知

import requests
def lineNotifyMessage(token, msg):
	headers = {
		"Authorization": "Bearer " + token,
		"Content-Type" : "application/x-www-form-urlencoded"
	}

	parameters = {'message': msg }
	r = requests.post("https://notify-api.line.me/api/notify", headers = headers, params = parameters)
	return r.status_code

主程式 main.py

import Sheety
import SkyscannerFlightSearch
import LineNotify

def getCarriersName(cheapestQuote_json,_id):
	carriersData=cheapestQuote_json.get('Carriers')
	for carriers in carriersData:
		carriersName = carriers.get('Name') if _id == carriers.get('CarrierId') else ''
		if carriersName:
			return carriersName
	return 'Sorry! Not match airport'

def getPlaceName(cheapestQuote_json,_id):
	placeData = cheapestQuote_json.get('Places')
	for place in placeData:
		placeName = place.get('Name') if _id == place.get('PlaceId') else ''
		if placeName:
			return placeName
	return 'Sorry! Not match Place'

def getOutboundMeg(cheapestQuote_json,outboundData):
	outboundDepartureDate = outboundData.get('DepartureDate')
	outboundCarrierId = outboundData.get('CarrierIds')[0]
	outboundCarrierName = getCarriersName(cheapestQuote_json, outboundCarrierId)
	outboundPlaceOriginId = outboundData.get('OriginId')
	outboundPlaceOriginName = getPlaceName(cheapestQuote_json, outboundPlaceOriginId)
	outboundPlaceDestinationId = outboundData.get('DestinationId')
	outboundPlaceDestinationName = getPlaceName(cheapestQuote_json, outboundPlaceDestinationId)

	outboundMsg = '預計出國時間:' +outboundDepartureDate + '\n' \
				+ '班機:' + outboundCarrierName + '\n' \
				+ '搭機地點:' + outboundPlaceOriginName + '\n' \
				+ '抵達地點:' + outboundPlaceDestinationName + '\n'

	return outboundMsg

def getInboundMeg(cheapestQuote_json,inboundData):
	inboundDepartureDate = inboundData.get('DepartureDate')
	inboundCarrierId = inboundData.get('CarrierIds')[0]
	inboundCarrierName = getCarriersName(cheapestQuote_json, inboundCarrierId)
	inboundPlaceOriginId = inboundData.get('OriginId')
	inboundPlaceOriginName = getPlaceName(cheapestQuote_json, inboundPlaceOriginId)
	inboundPlaceDestinationId = inboundData.get('DestinationId')
	inboundPlaceDestinationName = getPlaceName(cheapestQuote_json, inboundPlaceDestinationId)

	inboundMsg = '預計回國時間:' + inboundDepartureDate + '\n' \
				  + '班機:' + inboundCarrierName + '\n' \
				  + '搭機地點:' + inboundPlaceOriginName + '\n' \
				  + '抵達地點:' + inboundPlaceDestinationName

	return inboundMsg

if __name__ == '__main__':
	LINENOTIFY_TOKEN = 'MgQ7EoyyCv5JPacBcrZaYeyRSMCtQH8iXLUiDAz98ml'
	ourFlight = Sheety.getFlightInformation()

	for flight in ourFlight.get('flightInformation'):
		country = flight.get('country')
		currency = flight.get('currency')
		locale = flight.get('locale')
		originPlace = flight.get('originPlace')
		destinationPlace = flight.get('destinationPlace')
		outboundPartialDate = flight.get('outboundPartialDate')
		inboundPartialDate = flight.get('inboundPartialDate')

		cheapestQuote_json=SkyscannerFlightSearch.getCheapestQuotes(country,currency
						,locale,originPlace,destinationPlace,outboundPartialDate,inboundPartialDate)

		for quote in  cheapestQuote_json.get('Quotes'):
			minPrice= quote.get('MinPrice')
			direct = quote.get('Direct')

			outboundMsg = getOutboundMeg(cheapestQuote_json,quote.get('OutboundLeg'))
			inboundMsg = getInboundMeg(cheapestQuote_json,quote.get('InboundLeg'))

			notifyMsg = '價錢:' + str(minPrice) +'\n' \
						'是否為直達:' + str(direct) + '\n' \
						+outboundMsg+inboundMsg

			LineNotify.lineNotifyMessage(LINENOTIFY_TOKEN,notifyMsg)
1個讚

請問我執行程式 出現下列這段代碼,是哪裡出問題了,抱歉,我已經上網查過,也嘗試著自己解決,但真的找不出問題點,只好向大家求救,麻煩各位先進幫忙看看,先謝過各位了。

C:\Users\jeff\PycharmProjects\Day39_Skyscanner\venv\Scripts\python.exe C:/Users/jeff/PycharmProjects/Day39_Skyscanner/main.py
Traceback (most recent call last):
  File "C:\Users\jeff\PycharmProjects\Day39_Skyscanner\main.py", line 62, in <module>
    for flight in ourFlight.get('flightInformation') :
TypeError: 'NoneType' object is not iterable

Process finished with exit code 1

line 62:

if __name__ == '__main__' :
    LINENOTIFY_TOKEN = 'XXXXXXXXXXXXXXXXXXXX'  # 這段我隱藏沒秀出
    ourFlight = Sheety.getFlightInformation()

    for flight in ourFlight.get('flightInformation') :
        country = flight.get('country')
        currency = flight.get('currency')
        locale = flight.get('locale')
        originPlace = flight.get('originPlace')
        destinationPlace = flight.get('destinationPlace')
        outboundPartialDate = flight.get('outboundPartialDate')
        inboundPartialDate = flight.get('inboundPartialDate')

        cheapestQuote_json = SkyscannerFlightSearch.getCheapestQuotes(country, currency, locale,
                                                                      originPlace, destinationPlace,
                                                                      outboundPartialDate, inboundPartialDate)

        for quote in cheapestQuote_json.get('Quotes') :
            minPrice = quote.get('MinPrice')
            direct = quote.get('Direct')

            outboundMsg = getOutboundMeg(cheapestQuote_json, quote.get('OutboundLeg'))
            inboundMsg = getInboundMeg(cheapestQuote_json, quote.get('InboundLeg'))

            notifyMsg = '價錢:' + str(minPrice) + '\n' \
                                                '是否為直達:' + str(direct) + '\n' \
                        + outboundMsg + inboundMsg
            LineNotify.lineNotifyMessage(LINENOTIFY_TOKEN, notifyMsg)

Hi Jeff33:
我覺得可能是與sheety的連結有關係,
所以可能可以檢查看看以下幾個點:
1.檢查與Sheety的url是否有誤
2.檢查google sheet中的工作表是否有flightInformation的工作表

2個讚

感謝Shadow大的協助,抱歉這麼晚才來感謝,因後來身邊有其他事,就先跳過沒再處理這個問題,當時打算繼續學下去,等功力深一點後,再回頭重溫可能就看得懂了。

今天回頭看自己的程式碼,已經有點太複雜看得很吃力,似乎是像您說的 google sheet中的工作表找不到flightInformation的工作表,不過可能需要回頭看老師的影片重溫,屆時再來驗證是不是這個問題所致,不過非常謝謝您的協助,讓我可以有查詢的方向,謝謝!

1個讚