152 行
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			152 行
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python
 | |
| 
 | |
| import argparse
 | |
| import configparser
 | |
| import os
 | |
| import urllib.request
 | |
| from bs4 import BeautifulSoup
 | |
| from aman.types.PerformanceData import PerformanceData
 | |
| 
 | |
| def findAircraftPages(rooturl : str, suburl : str):
 | |
|     aircrafts = []
 | |
| 
 | |
|     with urllib.request.urlopen(rooturl + suburl) as site:
 | |
|         data = site.read().decode('utf-8')
 | |
|         site.close()
 | |
| 
 | |
|         parsed = BeautifulSoup(data, features='lxml')
 | |
| 
 | |
|         for link in parsed.body.find_all('a', title=True):
 | |
|             split = link['href'].split('/')
 | |
|             if 3 == len(split) and split[2] == link['title'] and 'Category' not in link['title'] and 'Special' not in link['href']:
 | |
|                 aircrafts.append(rooturl + link['href'])
 | |
| 
 | |
|         for link in parsed.body.find_all('a', attrs={ 'title': 'Category:Aircraft' }):
 | |
|             if 'previous' not in link.text:
 | |
|                 aircrafts.extend(findAircraftPages(rooturl, link['href']))
 | |
| 
 | |
|     return aircrafts
 | |
| 
 | |
| def findAndParseEntry(tableRow, startIdx, substring, default):
 | |
|     while 0 < startIdx:
 | |
|         if substring in tableRow[startIdx].text:
 | |
|             split = tableRow[startIdx].text.split(' ')
 | |
|             if 1 >= len(split):
 | |
|                 return default, startIdx - 2
 | |
|             else:
 | |
|                 return int(split[0]), startIdx - 2
 | |
|         else:
 | |
|             startIdx -= 1
 | |
| 
 | |
|     return 0, -1
 | |
| 
 | |
| def findAndParseSpeedEntry(tableRow, startIdx, default):
 | |
|     return findAndParseEntry(tableRow, startIdx, 'kts', default)
 | |
| 
 | |
| def findAndParseRodEntry(tableRow, startIdx, default):
 | |
|     return findAndParseEntry(tableRow, startIdx, 'ft/min', default)
 | |
| 
 | |
| def parsePerformanceEntries(tableRowSpeeds, tableRowRODs):
 | |
|     speeds = []
 | |
|     rods = []
 | |
| 
 | |
|     # parse the speed data
 | |
|     idx = len(tableRowSpeeds) - 1
 | |
|     while 0 < idx:
 | |
|         parsed = findAndParseSpeedEntry(tableRowSpeeds, idx, 140 if 0 == len(speeds) else 250)
 | |
|         if 0 < idx:
 | |
|             speeds.append(parsed[0])
 | |
|             idx = parsed[1]
 | |
| 
 | |
|     # parse the ROD data
 | |
|     idx = len(tableRowRODs) - 1
 | |
|     while 0 < idx:
 | |
|         parsed = findAndParseRodEntry(tableRowRODs, idx, 2000)
 | |
|         if 0 < idx:
 | |
|             rods.append(parsed[0])
 | |
|             idx = parsed[1]
 | |
| 
 | |
|     return speeds, rods
 | |
| 
 | |
| def parsePerformanceData(url : str):
 | |
|     with urllib.request.urlopen(url) as site:
 | |
|         data = site.read().decode('utf-8')
 | |
|         site.close()
 | |
| 
 | |
|         # check if we find the ICAO code
 | |
|         parsed = BeautifulSoup(data, features='lxml')
 | |
|         icao = parsed.body.find('h5', attrs={ 'id' : 'siteSub', 'class' : 'subtitle'})
 | |
|         if None == icao or '' == icao.text:
 | |
|             return False, None
 | |
| 
 | |
|         aircraft = PerformanceData(icao.text)
 | |
|         performanceTable = parsed.body.find('table', attrs={ 'class' : 'wikitable', 'style' : 'font-size: 90%;' })
 | |
|         if None == performanceTable or None == performanceTable.find_all('tr')[1] or None == performanceTable.find_all('tr')[2]:
 | |
|             return False, None
 | |
| 
 | |
|         speeds, rods = parsePerformanceEntries(performanceTable.find_all('tr')[1].find_all('td'),
 | |
|                                                performanceTable.find_all('tr')[2].find_all('td'))
 | |
|         if 10 > len(speeds):
 | |
|             speeds.insert(1, speeds[1])
 | |
| 
 | |
|         # create the speed data
 | |
|         if len(speeds) >= 4:
 | |
|             aircraft.speedApproach = speeds[0]
 | |
|             aircraft.speedBelowFL100 = speeds[1]
 | |
|             aircraft.speedAboveFL100 = speeds[2]
 | |
|             aircraft.speedAboveFL240 = speeds[3]
 | |
|         # create the ROD data
 | |
|         if len(rods) >= 3:
 | |
|             aircraft.rodBelowFL100 = rods[0]
 | |
|             aircraft.rodAboveFL100 = rods[1]
 | |
|             aircraft.rodAboveFL240 = rods[2]
 | |
| 
 | |
|         return len(speeds) >= 4 and len(rods) >= 3, aircraft
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     # create the commandline parser
 | |
|     parser = argparse.ArgumentParser(description='Extract the aircraft performace data')
 | |
|     parser.add_argument('directory', help='Directory where to store the performance data configuration')
 | |
|     args = parser.parse_args()
 | |
| 
 | |
|     # create the directory if it does not exist
 | |
|     if not os.path.exists(args.directory):
 | |
|         os.makedirs(args.directory)
 | |
| 
 | |
|     # parse the aircrafts
 | |
|     links = findAircraftPages('https://www.skybrary.aero', '/index.php?title=Category:Aircraft')
 | |
|     print('Found ' + str(len(links)) + ' aircrafts')
 | |
| 
 | |
|     aircrafts = []
 | |
|     parsed = 0
 | |
|     for link in links:
 | |
|         valid, aircraft = parsePerformanceData(link)
 | |
| 
 | |
|         parsed += 1
 | |
|         print('Parsed ' + str(parsed) + ' of ' + str(len(links)), end='\r')
 | |
| 
 | |
|         if False == valid:
 | |
|             print('Unable to find performance data for ' + link)
 | |
|             continue
 | |
| 
 | |
|         aircrafts.append(aircraft)
 | |
| 
 | |
|     print('Successfully parsed ' + str(len(aircrafts)) + ' of ' + str(len(links)) + ' aircrafts')
 | |
| 
 | |
|     # create the configuration file
 | |
|     config = configparser.ConfigParser()
 | |
|     for aircraft in aircrafts:
 | |
|         config[aircraft.icao] = {
 | |
|             'speedAboveFL240' : aircraft.speedAboveFL240,
 | |
|             'rodAboveFL240' : aircraft.rodAboveFL240,
 | |
|             'speedAboveFL100' : aircraft.speedAboveFL100,
 | |
|             'rodAboveFL100' : aircraft.rodAboveFL100,
 | |
|             'speedBelowFL100' : aircraft.speedBelowFL100,
 | |
|             'rodBelowFL100' : aircraft.rodBelowFL100,
 | |
|             'speedApproach' : aircraft.speedApproach
 | |
|         }
 | |
| 
 | |
|     # write the configuration data
 | |
|     with open(args.directory + '/PerformanceData.ini', 'w') as file:
 | |
|         config.write(file)
 |