Pull to refresh

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

Reading time16 min
Views37K

Введение


Всем читающим этот пост — здравствуйте.
Авиация — мое хобби, я об этом уже писал. Я готов часами стоять и фотографировать самолеты, смотреть видео о них, читать блоги летчиков, следить за трафиком на 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.

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


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

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


Ил-96 vs. Airbus A340


Boeing 737 vs. Airbus A320


Boeing 757 vs. Boeing 767


Airbus A330 vs. Boeing 777


Як-42 vs. Ту-154 vs. 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):
  # Пытаемся найти нужный ключ
  try:
      # Перебираем каждый ключ из propertyNames
      for propertyName in propertyNames:
          # Отсекаем ненужное  
          status = status[propertyName]
      
      # Нужный ключ найден!
      return status
   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
Tags:
Hubs:
Total votes 59: ↑58 and ↓1+57
Comments37

Articles