Flightstats API: Пишем свое табло прилетов с Боингами и Аэробусами

от автора

Введение

Всем читающим этот пост — здравствуйте.
Авиация — мое хобби, я об этом уже писал. Я готов часами стоять и фотографировать самолеты, смотреть видео о них, читать блоги летчиков, следить за трафиком на fr24.com. А еще мне нравится то, что в авиации кругом одни сокращения: ECAM, CDA, ACESS, APU и так далее. Вообщем, магия. А вот почти все люди из моего окружения к авиации равнодушны: «Ну самолет, как самолет. Большой, да. Что? Boeing 777-300ER? Ну ясно, ясно…». Но ничего не поделаешь, на вкус и цвет все фломастеры разные.
Как ко мне пришла идея поста? Так получилось, что я живу в 20 минутах езды от аэропорта Шереметьево. Как-то у меня выдался свободный час и приехал немного пофотографировать. За то время, пока я там был, мимо меня пролетело около 10 самолетов. Почти все — Аэрофлот. Я не спорю, у Аэрофлота есть интересные борты. Например, Добролет или Хохлома. Но в тот день мне не повезло, ничего подобного я не увидел. И тогда я подумал, что было бы очень полезно планировать подобные выезды. Вот так вот и родилась идея поста. Мне хотелось иметь следующий функционал: таблица вылетов — прилетов для выбранного аэропорта, выделение цветом как интересных, так и не очень ботов, экспорт в pdf.

Начинаем!

Итак, первым делом необходимо зайти на https://developer.flightstats.com, зарегистрироваться, перейти в Dashboard и нажать на кнопку «Create a new application». Это необходимо для получения связки AppId + AppKey, без которой доступ к API невозможен. Вообще, оно платное, но присутствует и бесплатный тарифный план — "Evaluation Plan", его возможностей для наших нужд хватит сполна. После этого смело идем "Get Started" -> "Flex API Reference" -> "Flight Status & Track API" -> "Flight Status & Track by Airport". В нижней части страницы есть раздел "Interactive Documentation", выбираем "Airport status (departures)". В данном запросе есть 7 обязательных полей, которые необходимо заполнить следующим образом:

appId appKey airport year month day hourOfDay
Ваш appId Ваш appKey SVO 2013 12 7 10

Через пару секунд появится ответ.

Иными словами мы попросили выдать нам информацию о рейсах, которые вылетят 7 декабря 2014 года после 10 часов из аэропорта Шереметьево. Да, SVO — Шереметьево. А еще UUEE — тоже Шереметьево. Помните, чуть выше я говорил о сокращениях? Вот, мы наткнулись на первое.

Коды аэропортов. IATA vs. ICAO

IATA — Международная ассоциация воздушного транспорта, ИАТА (англ. International Air Transport Association) международная неправительственная организация. Ассоциация выступает координатором и представителем интересов авиатранспортной отрасли в таких областях как обеспечение безопасности полетов, производство полетов, тарифная политика, техобслуживание, авиационная безопасность, разработка международных стандартов совместно с ИКАО и т. д.

ICAO — Международная организация гражданской авиации (International Civil Aviation Organization) — специализированное учреждение ООН, устанавливающее международные нормы гражданской авиации и координирующее её развитие с целью повышения безопасности и эффективности.

И у ИАТА и у ИКАО есть свои коды аэропортов. Они различны, поскольку коды ИАТА выбираются созвучными с названием аэропорта, а код ИКАО основан на том, где находится аэропорт. Именно поэтому у Шереметево код ИАТА SVO, а ИКАО — UUEE, для Пулково, например, LED и ULLI соответственно. Исключение составляют лишь аэропорты США (добавляется «K» к коду ИАТА: Лос-Анджелес — LAX — KLAX) и Канады (добавляется «С»: Торонто — YYZ — CYYZ).

Ответ flightstats

При данном запросе ответ имеет следующую структуру:

{   посланный запрос } "appendix": {   "airlines": {...}   "airports": {...}   "equipments": {...}   "flightStatuses": {...} } 

Секции airlines, airports и equipments содержат в себе описание авиакомпаний, аэропортов и типов самолетов, которые присутствуют в секции flightStatuses.
Секция «airlines» предельно проста:

"airlines": [    {     "fs": "SU",     "iata": "SU",     "icao": "AFL",     "name": "Aeroflot",     "active": true    }, ... 

Поле «fs» содержит в себе код авиакомпании в базе flightStats. Почти всегда он совпадает с кодом IATA.

Секция «airports» посложнее:

"airports": [    {     "fs": "BUD",     "iata": "BUD",     "icao": "LHBP",     "name": "Liszt Ferenc International Airport",     "city": "Budapest",     "cityCode": "BUD",     "countryCode": "HU",     "countryName": "Hungary",     "regionName": "Europe",     "timeZoneRegionName": "Europe/Budapest",     "localTime": "2013-12-06T20:51:56.974",     "utcOffsetHours": 1,     "latitude": 47.433037,     "longitude": 19.261621,     "elevationFeet": 495,     "classification": 2,     "active": true,     "delayIndexUrl": "https://api.flightstats.com/flex/delayindex/rest/v1/json/airports/BUD?codeType=fs",     "weatherUrl": "https://api.flightstats.com/flex/weather/rest/v1/json/all/BUD?codeType=fs"    },  ... 

Здесь содержится вся необходимая информация, кроме погоды и коэффициента задержки, которые надо запрашивать отдельно.

Секция «equipments».

"equipments": [    {     "iata": "319",     "name": "Airbus Industrie A319",     "turboProp": false,     "jet": true,     "widebody": false,     "regional": false    }, ... 

Описывает базовые характеристики самолета.

Отвлечемся вновь от API.

Учимся различать типы самолетов

Это совсем не сложно. Я подготовил небольшую схему, которая поможет легко сориентироваться в мире летающих машин.

И теперь подтвержение моих слов:
Airbus A380 vs. Boeing 747

Airbus A340

Boeing 737 vs. Airbus A320

Boeing 757 vs. Boeing 767

Airbus A330 vs. Boeing 777

McDonnel Douglas MD-11

Разбираем flightStatus

Срдержимое flightStatus. Длинное, поэтому скрыто

{    "flightId": 317846653,    "carrierFsCode": "SU",    "flightNumber": "2030",    "departureAirportFsCode": "SVO",    "arrivalAirportFsCode": "BUD",    "departureDate": {     "dateLocal": "2013-12-07T10:50:00.000",     "dateUtc": "2013-12-07T06:50:00.000Z"    },    "arrivalDate": {     "dateLocal": "2013-12-07T10:35:00.000",     "dateUtc": "2013-12-07T09:35:00.000Z"    },    "status": "L",    "schedule": {     "flightType": "J",     "serviceClasses": "RJY",     "restrictions": ""    },    "operationalTimes": {     "publishedDeparture": {      "dateLocal": "2013-12-07T10:50:00.000",      "dateUtc": "2013-12-07T06:50:00.000Z"     },     "publishedArrival": {      "dateLocal": "2013-12-07T10:35:00.000",      "dateUtc": "2013-12-07T09:35:00.000Z"     },     "scheduledGateDeparture": {      "dateLocal": "2013-12-07T10:50:00.000",      "dateUtc": "2013-12-07T06:50:00.000Z"     },     "estimatedGateDeparture": {      "dateLocal": "2013-12-07T10:50:00.000",      "dateUtc": "2013-12-07T06:50:00.000Z"     },     "actualGateDeparture": {      "dateLocal": "2013-12-07T11:27:00.000",      "dateUtc": "2013-12-07T07:27:00.000Z"     },     "scheduledGateArrival": {      "dateLocal": "2013-12-07T10:35:00.000",      "dateUtc": "2013-12-07T09:35:00.000Z"     },     "estimatedGateArrival": {      "dateLocal": "2013-12-07T11:12:00.000",      "dateUtc": "2013-12-07T10:12:00.000Z"     },     "actualGateArrival": {      "dateLocal": "2013-12-07T10:43:00.000",      "dateUtc": "2013-12-07T09:43:00.000Z"     }    },    "delays": {     "departureGateDelayMinutes": 37,     "arrivalGateDelayMinutes": 8    },    "flightDurations": {     "scheduledBlockMinutes": 165,     "blockMinutes": 136    },    "airportResources": {     "departureTerminal": "D",     "departureGate": "28",     "arrivalTerminal": "2"    },    "flightEquipment": {     "scheduledEquipmentIataCode": "320",     "actualEquipmentIataCode": "A320",     "tailNumber": "VP-BWI"    }   }, ... 

Назначение полей в большинстве случаев очевидно. Я подробно расскажу лишь о тех, содержимое которых не совсем очевидно. А почему? Правильно, потому что сокращения.
Вот эта часть ответа:

"status": "L",    "schedule": {     "flightType": "J",     "serviceClasses": "RJY",     "restrictions": ""    }, 

Поле Описание
status Текущий статус рейса
A — Active
C — Canceled
D — Diverted — Была произведена смена пункта назначения (например, по метео-условиям)
DN — Data source needed — Неоткуда получить информацию о статусе
L — Landed
NO — Not Operational
R — Redirected
S — Scheduled
U — Unknown
flightType Тип рейса. Всего их существует 23 штуки. Например,
J — Scheduled Passanger — Пассажириский по расписанию
M — Scheduled Cargo/Mail(MailOnly) — Грузовой, но только с письмами.
W — Military — Военный
serviceClasses Варианты сервиса, предусмотренные на рейсе по классификации IATA. Подробнее тут — http://en.wikipedia.org/wiki/IATA_class_codes
restrictions Ограничения по классификации IATA. Подробнее — http://www.flyerguide.com/wiki/index.php/Traffic_Restriction_Codes_(AA)

Программирование

На данный момент я использую python 2.7, urllib2 и simplejson.

Первое, что нужно сделать — подключить необходимые библиотеки и проинициализировать переменные.

import urllib2 import simplejson  appId = "Ваш appId тут" appKey = "Ваш appKey тут"  # Название аэропорта. Может быть запрошен как по внутреннему коду flightstats, так и по кодам ICAO или IATA requestedAirport = "SVO"  # Какие рейсы нам нужны. arr - прибывающие, dep - отбывающие flightsType = "arr"  # Дата  requestedDate = "2013/12/7"  # Время, с которого мы хотим получить список рейсов requestedHour = "15"  # Количество часов, за которые будет составлен список requestedNumHours = "6" 

Следующий шаг — упаковываем эти переменные в url, отправляем запрос и ждем ответа.

# Заготовка для запроса url = "https://api.flightstats.com/flex/flightstatus/rest/v2/json/" \        "airport/status/%s/%s/%s/%s?appId=%s&appKey=%s&utc=false&numHours=%s"   # Подставляем нужные значения в запрос         url = url %(requestedAirport, flightsType, requestedDate, requestedHour, appId, appKey, requestedNumHours)  # Шлем запрос и получаем JSON-ответ             req = urllib2.Request(url, None) opener = urllib2.build_opener() f = opener.open(req)          response = simplejson.load(f) 

Затем парсим вспомогательные поля. Они нам нужны для того, чтобы подставлять развернутые названия самолетов и аэропотов в список.

# Сохраняем ветку с аэропортами airports = response["appendix"]["airports"]  # Данные по аэропортам будут храниться в словаре (dictionary) airportsDict = dict()  # Для каждого аэропорта записываем пару [код flightstats]:[название] for airport in airports:     airportsDict[airport["fs"]] = airport["name"]  # Аналогично поступаем для типов бортов... equipments = response["appendix"]["equipments"] equipmentsDict = dict() for equipment in equipments:     equipmentsDict[equipment["iata"]] = equipment["name"], equipment["iata"]   #... и для авиакомпаний airlines = response["appendix"]["airlines"] airlinesDict = dict() for airline in airlines:     airlinesDict[airline["fs"]] = airline["name"] 

Результатом работы нашего кода должна быть вот такая таблица:

Flight Carrier Equipment Registration From STD ATD To STA STD
XQ114 SunExpress Boeing 737-800 Passenger D-ASXA Antalya 15:00:00.000 CGN 17:55:00.000

Выводить данные будем в HTML.

# Заготовка для страницы webPage = "<html><body><table border=\"1\">    \            <tr><th>Flight</th><th>Carrier</th><th>Equipment</th><th>Registration</th><th>From</th><th>STD</th>   \            <th>ATD</th><th>To</th><th>STA</th><th>ETA</th></tr>"  # Заготовка для строки таблицы templateRow = "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td> \                <td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>"  f = open("./list.html", "w") 

Далее необходимо написать вспомогательную функцию.
Нужные нам значения лежат на разной глубине. Например, carrierFsCode, код аэропорта, на нулевой глубине. А чтобы добыть время фактическое время вылета, нужно опуститься на вторую глубину: operationalTimes --> actualGateDeparture --> dateLocal". Для этого нужна первая вспомогательная функция.

def getProperty(status, propertyNames):   # Cохраняем все содержимое status   property = status    # Пытаемся найти нужный ключ   try:       # Перебираем каждый ключ из propertyNames       for propertyName in propertyNames:           # Отсекаем ненужное             property = property[propertyName]              # Нужный ключ найден!       return property    except       # А если нет, то возвращаем заглушку       return "---" 

Теперь самое интересное: необходимо выбрать то, что вас наиболее интересует в трафике. Это содержится в трех массивах:

interestingCarriers = ["RU", # AirBridgeCargo                        "CU", # Cubana de Aviacion                        "ME", # China Eastern Airlines                        "KE", # Korean Air Lines                        ] interestingEquipments = ["SU9"] # Sukhoi Superjet 100  interestingTailNumbers = ["VP-BGB"] # Номер первого Boeing 777-300ER для Аэрофлота 

А теперь, собственно, парсер:

for flightStatus in flightStatuses:     newRow = templateRow %(getProperty(flightStatus, ["carrierFsCode"]) + getProperty(flightStatus, ["flightNumber"]),                    airlinesDict[getProperty(flightStatus, ["carrierFsCode"])],                    getProperty(flightStatus, ["flightEquipment", "scheduledEquipmentIataCode"]),                    getProperty(flightStatus, ["flightEquipment", "tailNumber"]),                    str(airportsDict[getProperty(flightStatus, ["departureAirportFsCode"])]).replace("Airport", ""),                    str(getProperty(flightStatus, ["departureDate", "dateLocal"])).split("T")[-1],                    str(getProperty(flightStatus, ["operationalTimes", "actualGateDeparture", "dateLocal"])).split("T")[-1],                    str(airportsDict[getProperty(flightStatus, ["arrivalAirportFsCode"])]).replace("Airport", "")                    str(getProperty(flightStatus, ["arrivalDate", "dateLocal"])).split("T")[-1],                    str(getProperty(flightStatus, ["operationalTimes", "estimatedGateArrival", "dateLocal"])).split("T")[-1])      # Подсвечиваем необходимую строку     if (getProperty(flightStatus, ["carrierFsCode"]) in interestingCarriers) or \         (getProperty(flightStatus, ["flightEquipment", "scheduledEquipmentIataCode"]) in interestingEquipments) or \         (getProperty(flightStatus, ["flightEquipment", "tailNumber"]) in interestingTailNumbers):         newRow = newRow.replace("<tr>", "<tr bgcolor=\"#FF0000\">")          #  Добавляем ее к странице     webPage += newRow 

Завершающий штрих — дописываем теги в конец страницы и закрываем файл.

webPage = webPage + "</table></body></html>" f.write(webPage) f.close() 

Результат работы

Flight Carrier Equipment Registration From STD ATD To STA ETA
SU155 Aeroflot 332 VQ-BBE Cancun International 12:30:00.000 13:17:00.000 Sheremetyevo International 10:30:00.000 11:03:00.000
DL466 Delta Air Lines 76W John F. Kennedy International 16:15:00.000 16:14:00.000 Sheremetyevo International 10:50:00.000 10:12:00.000
SU111 Aeroflot 332 VP-BLX Miami International 17:35:00.000 18:35:00.000 Sheremetyevo International 13:45:00.000 13:46:00.000
SU103 Aeroflot 333 VP-BDE John F. Kennedy International 19:05:00.000 Sheremetyevo International 13:25:00.000 13:34:00.000
UN576 Transaero Airlines 744 EI-XLJ Punta Cana International 19:55:00.000 21:18:00.000 Sheremetyevo International 14:50:00.000 15:35:00.000
RU566 AirBridgeCargo 74Y Frankfurt am Main 04:45:00.000 Sheremetyevo International 11:00:00.000
RU498 AirBridgeCargo 74N Shanghai Pudong International 05:00:00.000 Sheremetyevo International 10:45:00.000
SU233 Aeroflot 332 Indira Gandhi International 05:05:00.000 05:26:00.000 Sheremetyevo International 10:10:00.000 10:13:00.000
RU506 AirBridgeCargo 74N Milano Malpensa 05:30:00.000 Sheremetyevo International 12:00:00.000
SU1827 Aeroflot 320 VQ-BAZ Simferopol 06:00:00.000 06:25:00.000 Sheremetyevo International 10:15:00.000 10:40:00.000
SU2437 Aeroflot 320 VP-BLH Dusseldorf International 06:05:00.000 06:27:00.000 Sheremetyevo International 12:25:00.000 12:24:00.000
RU440 AirBridgeCargo 74N VP-BIM Hong Kong International 06:15:00.000 06:15:00.000 Sheremetyevo International 12:25:00.000
KE529 Korean Air Lines 74Y HL7466 Incheon International 06:25:00.000 07:07:00.000 Sheremetyevo International 10:40:00.000
JU650 Jat Airways 733 Belgrad Nikola Tesla 06:45:00.000 06:45:00.000 Sheremetyevo International 12:35:00.000 12:39:00.000
PS561 UIA 73N UR-GAP Kiev/Kyiv — Borispol 07:00:00.000 07:00:00.000 Sheremetyevo International 10:35:00.000 10:35:00.000
SU1009 Aeroflot 321 VQ-BED Kaliningrad 07:10:00.000 07:36:00.000 Sheremetyevo International 10:00:00.000 10:26:00.000
AF1644 Air France 319 F-GRHL Charles de Gaulle 07:15:00.000 07:13:00.000 Sheremetyevo International 13:55:00.000 13:52:00.000
SU1867 Aeroflot 320 VP-BQP Zvartnots International 08:10:00.000 08:21:00.000 Sheremetyevo International 11:00:00.000 11:11:00.000
5N502 Nordavia Regional Airlines 735 Syktyvkar 08:20:00.000 08:27:00.000 Sheremetyevo International 10:15:00.000 10:11:00.000
KC893 Air Astana 320 P4-KBC Astana 08:40:00.000 08:36:00.000 Sheremetyevo International 10:20:00.000 10:49:00.000
SU3 Aeroflot 321 VP-BWO Pulkovo 08:55:00.000 09:04:00.000 Sheremetyevo International 10:20:00.000 10:29:00.000
SU1513 Aeroflot 319 VP-BWA Surgut 09:00:00.000 08:59:00.000 Sheremetyevo International 10:35:00.000 10:34:00.000
SU1293 Aeroflot 320 VQ-BIV Kazan 09:00:00.000 09:27:00.000 Sheremetyevo International 10:30:00.000 10:50:00.000
SU1229 Aeroflot 320 VP-BDK Nizhniy Novgorod 09:05:00.000 09:21:00.000 Sheremetyevo International 10:25:00.000 10:41:00.000
SU1309 Aeroflot 319 VP-BDO Samara 09:15:00.000 09:20:00.000 Sheremetyevo International 10:55:00.000 11:00:00.000
AY153 Finnair 319 OH-LVI Helsinki-Vantaa 09:25:00.000 09:29:00.000 Sheremetyevo International 13:05:00.000 12:57:00.000
OK892 CSA 319 Vaclav Havel Prague 09:30:00.000 09:31:00.000 Sheremetyevo International 15:10:00.000 15:05:00.000
SU2005 Aeroflot 320 VP-BWI J. Paul II International Krakow-Balice 09:35:00.000 09:56:00.000 Sheremetyevo International 14:40:00.000 14:49:00.000
SU1121 Aeroflot 320 VP-BTI Adler/Sochi 09:50:00.000 09:55:00.000 Sheremetyevo International 12:20:00.000 12:25:00.000
SU2685 Aeroflot 320 VQ-BCM Schoenefeld 09:50:00.000 10:44:00.000 Sheremetyevo International 15:25:00.000 16:15:00.000
SU5 Aeroflot 320 VQ-BAX Pulkovo 09:55:00.000 10:20:00.000 Sheremetyevo International 11:15:00.000 11:40:00.000
SU1839 Aeroflot SU9 RA-89010 Kharkov 09:55:00.000 10:10:00.000 Sheremetyevo International 13:30:00.000 13:20:00.000
SU2321 Aeroflot 320 VQ-BHL Franz Josef Strauss 10:00:00.000 10:16:00.000 Sheremetyevo International 16:00:00.000 16:16:00.000
SU1001 Aeroflot 320 VP-BLL Kaliningrad 10:05:00.000 10:25:00.000 Sheremetyevo International 12:55:00.000 13:15:00.000
R25807 Orenair 738 Barnaul 10:10:00.000 10:15:00.000 Sheremetyevo International 11:30:00.000 11:35:00.000
SU1307 Aeroflot 320 VP-BKX Tolmachevo 10:15:00.000 10:19:00.000 Sheremetyevo International 11:25:00.000 11:29:00.000
SU1701 Aeroflot 333 VQ-BNS Vladivostok International 10:20:00.000 10:24:00.000 Sheremetyevo International 12:25:00.000 12:29:00.000
SU1805 Aeroflot 321 VP-BOE Kiev/Kyiv — Borispol 10:20:00.000 11:00:00.000 Sheremetyevo International 13:50:00.000 14:30:00.000
SU2137 Aeroflot 321 VQ-BHK Istanbul Ataturk 10:20:00.000 11:03:00.000 Sheremetyevo International 15:15:00.000 15:26:00.000
SK734 SAS 320 OY-KAP Copenhagen 10:20:00.000 10:46:00.000 Sheremetyevo International 15:45:00.000 16:02:00.000
SU7 Aeroflot 320 Pulkovo 10:25:00.000 10:43:00.000 Sheremetyevo International 11:45:00.000 12:03:00.000
SU1813 Aeroflot 320 VP-BRX Donetsk 10:30:00.000 10:31:00.000 Sheremetyevo International 14:25:00.000 14:26:00.000
SU1831 Aeroflot 320 Minsk International 2 10:50:00.000 11:40:00.000 Sheremetyevo International 13:15:00.000 14:05:00.000
SU2107 Aeroflot 320 VP-BZS Tallinn 10:50:00.000 10:54:00.000 Sheremetyevo International 14:30:00.000 14:18:00.000
SU1479 Aeroflot 319 VP-BDM Abakan 10:55:00.000 10:55:00.000 Sheremetyevo International 11:55:00.000 11:55:00.000
SU1483 Aeroflot 77W VP-BGB Krasnojarsk 11:00:00.000 11:13:00.000 Sheremetyevo International 11:35:00.000 11:48:00.000
SU2683 Aeroflot 319 VQ-BCO Riga 11:00:00.000 11:24:00.000 Sheremetyevo International 14:35:00.000 14:44:00.000
D95399 Donavia 319 VP-BNN Stavropol 11:15:00.000 11:17:00.000 Sheremetyevo International 13:30:00.000 13:32:00.000
SU2035 Aeroflot SU9 RA-89008 Otopeni International 11:15:00.000 11:28:00.000 Sheremetyevo International 15:35:00.000 15:33:00.000
SU11 Aeroflot 320 Pulkovo 11:30:00.000 11:49:00.000 Sheremetyevo International 12:45:00.000 13:04:00.000
SU1139 Aeroflot 321 VQ-BKU Adler/Sochi 11:35:00.000 11:55:00.000 Sheremetyevo International 14:00:00.000 14:20:00.000
SU1211 Aeroflot 320 VQ-BIT Samara 11:40:00.000 12:13:00.000 Sheremetyevo International 13:25:00.000 13:42:00.000
SU1759 Aeroflot SU9 VP-BZQ Volgograd 11:45:00.000 11:53:00.000 Sheremetyevo International 13:35:00.000 13:43:00.000
SU1255 Aeroflot 319 VP-BDN Begishevo 11:50:00.000 12:03:00.000 Sheremetyevo International 13:40:00.000 13:53:00.000
SU1643 Aeroflot 320 VQ-BIW Astrakhan 11:50:00.000 11:55:00.000 Sheremetyevo International 14:10:00.000 14:15:00.000
SU1305 Aeroflot 320 VP-BLP Mineralnye Vody 11:50:00.000 12:08:00.000 Sheremetyevo International 14:15:00.000 14:33:00.000
SU1761 Aeroflot 738 VP-BRH Chita 11:55:00.000 12:10:00.000 Sheremetyevo International 12:45:00.000 13:00:00.000
SU1221 Aeroflot 320 VP-BMF Nizhniy Novgorod 12:05:00.000 12:12:00.000 Sheremetyevo International 13:10:00.000 13:17:00.000
SU1743 Aeroflot 333 VQ-BQX Yuzhno-Sakhalinsk 12:10:00.000 12:20:00.000 Sheremetyevo International 14:05:00.000 14:15:00.000
D95301 Donavia 734 VQ-BCS Rostov 12:15:00.000 12:28:00.000 Sheremetyevo International 14:15:00.000 14:28:00.000
SU13 Aeroflot 319 Pulkovo 12:20:00.000 12:50:00.000 Sheremetyevo International 13:35:00.000 14:05:00.000
5N117 Nordavia Regional Airlines 735 Arkhangelsk 12:20:00.000 12:25:00.000 Sheremetyevo International 14:05:00.000 14:10:00.000
SU1191 Aeroflot 320 VQ-BEA Kazan 12:25:00.000 13:04:00.000 Sheremetyevo International 13:55:00.000 14:34:00.000
SU1751 Aeroflot 738 VP-BRF Yakutsk 12:30:00.000 12:58:00.000 Sheremetyevo International 13:15:00.000 13:43:00.000
SU1547 Aeroflot SU9 Anapa 12:30:00.000 12:50:00.000 Sheremetyevo International 14:45:00.000 15:05:00.000
D95377 Donavia 319 Mineralnye Vody 12:45:00.000 13:03:00.000 Sheremetyevo International 15:10:00.000 15:28:00.000
D95363 Donavia 319 VP-BQK Rostov 13:05:00.000 13:20:00.000 Sheremetyevo International 15:05:00.000 15:20:00.000
SU1411 Aeroflot 321 VQ-BOI Koltsovo International 13:15:00.000 13:43:00.000 Sheremetyevo International 13:40:00.000 14:08:00.000
SU1731 Aeroflot 333 VQ-BCQ Petropavlovsk-Kamchatsky 13:30:00.000 13:44:00.000 Sheremetyevo International 14:30:00.000 14:44:00.000
SU15 Aeroflot 320 Pulkovo 13:30:00.000 13:39:00.000 Sheremetyevo International 14:45:00.000 14:52:00.000
SU1231 Aeroflot 320 VP-BLR Ufa 13:55:00.000 14:19:00.000 Sheremetyevo International 14:00:00.000 14:24:00.000
SU1421 Aeroflot 320 VP-BNL Chelyabinsk 13:55:00.000 13:56:00.000 Sheremetyevo International 14:20:00.000 14:21:00.000
R25803 Orenair 738 Irkutsk 14:05:00.000 14:30:00.000 Sheremetyevo International 14:50:00.000 15:15:00.000
SU1201 Aeroflot SU9 Perm 14:10:00.000 Sheremetyevo International 14:25:00.000 14:25:00.000
5N9134 Nordavia Regional Airlines Kazan 14:10:00.000 15:07:00.000 Sheremetyevo International 15:30:00.000
SU17 Aeroflot 320 Pulkovo 14:25:00.000 14:56:00.000 Sheremetyevo International 15:40:00.000 16:11:00.000

Future work

  • Хочу сделать более красивый вид таблицы результатами
  • Нормальный вывод в PDF, а не как печать web-страницы
  • Приложение для Android

ссылка на оригинал статьи http://habrahabr.ru/post/205210/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *