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