Finding the cheapest flights for a multi-leg trip with Amadeus API and Python



This summer I’m planning to have a trip that will include Moscow, Irkutsk, Beijing, Shanghai, and Tokyo. As I’m flexible on dates I’ve decided to try to find the cheapest flights with the shortest duration. I’ve tried to do this before twice by parsing Google Flights, it was successful, but I don’t want to update those hackish scripts and want to try something a bit saner.

So I chose to try Amadeus API. It was a bit painful to use, some endpoints were randomly failing with 500, and they needed a signed agreement to use real data. But overall it was at least better than parsing Google Flights, and the whole adventure fit inside the free quota for requests.

TLDR: jupyter notebook with the whole adventure

Restrictions

I’m flexible but with boundaries, so I’ll be able to start between 10th and 20th of July and travel no longer than 21 days:

min_start = date ( 2019 , 7 , 10 ) max_start = date ( 2019 , 7 , 20 ) max_days = 21

I mostly don’t want to have multi-segment flights and know how many days I want to spend in destinations:

places_df = pd . DataFrame ([( 'Amsterdam' , 'NL' , 0 , ( max_start - min_start ). days , True ), # for enabling tentative start date ( 'Moscow' , 'RU' , 3 , 5 , True ), ( 'Irkutsk' , 'RU' , 7 , 10 , True ), ( 'Beijing' , 'CN' , 3 , 5 , True ), ( 'Shanghai' , 'CN' , 3 , 5 , True ), ( 'Tokyo' , 'JP' , 3 , 5 , False ), ( 'Amsterdam' , 'NL' , 0 , 0 , True )], # the final destination columns = [ 'city' , 'cc' , 'min_days' , 'max_days' , 'only_direct' ]) places_df [ 'min_day_of_dep' ] = places_df . min_days . rolling ( min_periods = 1 , window = len ( places_df )). sum () places_df [ 'max_day_of_dep' ] = places_df . max_days . rolling ( min_periods = 1 , window = len ( places_df )). sum () places_df

city cc min_days max_days only_direct min_day_of_dep max_day_of_dep 0 Amsterdam NL 0 10 True 0.0 10.0 1 Moscow RU 3 5 True 3.0 15.0 2 Irkutsk RU 7 10 True 10.0 25.0 3 Beijing CN 3 5 True 13.0 30.0 4 Shanghai CN 3 5 True 16.0 35.0 5 Tokyo JP 3 5 False 19.0 40.0 6 Amsterdam NL 0 0 True 19.0 40.0

Airports

A lot of big cities have more than one airport, and usually, some airports are for low-costers and some for pricier flights. But the most important that the API expects me to send IATA codes to get prices for dates. So I needed to get IATA codes for airports for cities I will travel through, and it’s possible with just a request to /reference-data/locations:

def get_iata ( city , cc ): response = call_api ( '/reference-data/locations' , # full code in the notebook keyword = city , countryCode = cc , subType = 'AIRPORT' ) return [ result [ 'iataCode' ] for result in response [ 'data' ]] get_iata ( 'Moscow' , 'RU' )

[ 'DME' , 'SVO' , 'VKO' ]

With that function, I was able to get IATA codes for all destinations and get all possible routes with a bit of pandas magic:

places_df [ 'iata' ] = places_df . apply ( lambda place : get_iata ( place [ 'city' ], place [ 'cc' ]), axis = 1 ) routes_df = places_df . assign ( dest_iata = places_df . iloc [ 1 :]. reset_index (). iata ) routes_df [ 'routes' ] = routes_df . apply ( lambda row : [ * product ( row [ 'iata' ], row [ 'dest_iata' ])] if isinstance ( row [ 'dest_iata' ], list ) else [], axis = 1 ) routes_df = routes_df . routes \ . apply ( pd . Series ) \ . merge ( routes_df , right_index = True , left_index = True ) \ . drop ([ 'routes' , 'min_days' , 'max_days' , 'iata' , 'dest_iata' ], axis = 1 ) \ . melt ( id_vars = [ 'city' , 'cc' , 'min_day_of_dep' , 'max_day_of_dep' , 'only_direct' ], value_name = "route" ) \ . drop ( 'variable' , axis = 1 ) \ . dropna () routes_df [ 'origin' ] = routes_df . route . apply ( lambda route : route [ 0 ]) routes_df [ 'destination' ] = routes_df . route . apply ( lambda route : route [ 1 ]) routes_df = routes_df \ . drop ( 'route' , axis = 1 ) \ . rename ( columns = { 'city' : 'origin_city' , 'cc' : 'origin_cc' }) routes_df . head ( 10 )

origin_city origin_cc min_day_of_dep max_day_of_dep only_direct origin destination 0 Amsterdam NL 0.0 10.0 True AMS DME 1 Moscow RU 3.0 15.0 True DME IKT 2 Irkutsk RU 10.0 25.0 True IKT PEK 3 Beijing CN 13.0 30.0 True PEK PVG 4 Shanghai CN 16.0 35.0 True PVG HND 5 Tokyo JP 19.0 40.0 False HND AMS 7 Amsterdam NL 0.0 10.0 True AMS SVO 8 Moscow RU 3.0 15.0 True SVO IKT 9 Irkutsk RU 10.0 25.0 True IKT NAY 10 Beijing CN 13.0 30.0 True PEK SHA

To understand the complexity of the problem better I draw an ugly graph of possible flights routes:

After that I’ve calculated all possible dates for flights:

route_dates_df = routes_df . assign ( dates = routes_df . apply ( lambda row : [ min_start + timedelta ( days = days ) for days in range ( int ( row . min_day_of_dep ), int ( row . max_day_of_dep ) + 1 )], axis = 1 )) route_dates_df = route_dates_df . dates \ . apply ( pd . Series ) \ . merge ( route_dates_df , right_index = True , left_index = True ) \ . drop ([ 'dates' , 'min_day_of_dep' , 'max_day_of_dep' ], axis = 1 ) \ . melt ( id_vars = [ 'origin_city' , 'origin_cc' , 'origin' , 'destination' , 'only_direct' ], value_name = "date" ) \ . drop ( 'variable' , axis = 1 ) \ . dropna () valid_routes_df = route_dates_df [ route_dates_df . date <= max_start + timedelta ( days = max_days )] valid_routes_df . head ( 10 )

origin_city origin_cc origin destination only_direct date 0 Amsterdam NL AMS DME True 2019-07-10 1 Moscow RU DME IKT True 2019-07-13 2 Irkutsk RU IKT PEK True 2019-07-20 3 Beijing CN PEK PVG True 2019-07-23 4 Shanghai CN PVG HND True 2019-07-26 5 Tokyo JP HND AMS False 2019-07-29 6 Amsterdam NL AMS SVO True 2019-07-10 7 Moscow RU SVO IKT True 2019-07-13 8 Irkutsk RU IKT NAY True 2019-07-20 9 Beijing CN PEK SHA True 2019-07-23

Eventually, I’ve got 363 possible route-date combinations, and used /shopping/flight-offers to get prices. As the endpoint has a quota of 2000 free requests, I was able to mess everything up a few times and haven’t reached it yet:

def get_prices ( origin , destination , date , only_direct ): response = call_api ( '/shopping/flight-offers' , origin = origin , destination = destination , nonStop = 'true' if only_direct else 'false' , departureDate = date . strftime ( "%Y-%m-%d" )) if 'data' not in response : print ( response ) return [] return [( origin , destination , date , Decimal ( offer_item [ 'price' ][ 'total' ]), parse_date ( offer_item [ 'services' ][ 0 ][ 'segments' ][ 0 ][ 'flightSegment' ][ 'departure' ][ 'at' ]), parse_date ( offer_item [ 'services' ][ 0 ][ 'segments' ][ - 1 ][ 'flightSegment' ][ 'arrival' ][ 'at' ]), len ( offer_item [ 'services' ][ 0 ][ 'segments' ])) for flight in response [ 'data' ] for offer_item in flight [ 'offerItems' ]] get_prices ( 'IKT' , 'PEK' , date ( 2019 , 7 , 20 ), True )[: 5 ]

[( 'IKT' , 'PEK' , datetime . date ( 2019 , 7 , 20 ), Decimal ( '209.11' ), datetime . datetime ( 2019 , 7 , 20 , 1 , 50 , tzinfo = tzoffset ( None , 28800 )), datetime . datetime ( 2019 , 7 , 20 , 4 , 40 , tzinfo = tzoffset ( None , 28800 )), 1 ), ( 'IKT' , 'PEK' , datetime . date ( 2019 , 7 , 20 ), Decimal ( '262.98' ), datetime . datetime ( 2019 , 7 , 20 , 15 , 15 , tzinfo = tzoffset ( None , 28800 )), datetime . datetime ( 2019 , 7 , 20 , 18 , 5 , tzinfo = tzoffset ( None , 28800 )), 1 )]

Then I’ve fetched flights for the whole set of dates, assigned useful metadata like origin/destination cities and duration of the flights, and removed flights pricier than €800:

prices_df = pd . DataFrame ([ price for route in valid_routes_df . to_dict ( 'record' ) for price in get_prices ( route [ 'origin' ], route [ 'destination' ], route [ 'date' ], route [ 'only_direct' ])], columns = [ 'origin' , 'destination' , 'date' , 'price' , 'departure_at' , 'arrival_at' , 'segments' ]) airport_to_city = dict ( zip ( routes_df . origin , routes_df . origin_city )) prices_with_city_df = prices_df \ . assign ( duration = prices_df . arrival_at - prices_df . departure_at , origin_city = prices_df . origin . apply ( airport_to_city . __getitem__ ), destination_city = prices_df . destination . apply ( airport_to_city . __getitem__ )) prices_with_city_df [ 'route' ] = prices_with_city_df . origin_city + " ✈️ " + prices_with_city_df . destination_city valid_prices_with_city_df = prices_with_city_df [ prices_with_city_df . price <= 800 ] valid_prices_with_city_df . head ()

origin destination date price departure_at arrival_at segments duration origin_city destination_city route 0 DME IKT 2019-07-13 257.40 2019-07-13 21:40:00+03:00 2019-07-14 08:25:00+08:00 1 05:45:00 Moscow Irkutsk Moscow✈️Irkutsk 1 DME IKT 2019-07-13 257.40 2019-07-13 23:00:00+03:00 2019-07-14 09:45:00+08:00 1 05:45:00 Moscow Irkutsk Moscow✈️Irkutsk 2 DME IKT 2019-07-13 254.32 2019-07-13 19:55:00+03:00 2019-07-14 06:25:00+08:00 1 05:30:00 Moscow Irkutsk Moscow✈️Irkutsk 3 DME IKT 2019-07-13 227.40 2019-07-13 18:30:00+03:00 2019-07-14 05:15:00+08:00 1 05:45:00 Moscow Irkutsk Moscow✈️Irkutsk 4 IKT PEK 2019-07-20 209.11 2019-07-20 01:50:00+08:00 2019-07-20 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk✈️Beijing

To have a brief overview of prices I’ve made a scatterplot. If I was a machine learning algorithm I would exclude Tokyo from the adventure:

Itinerary

At this stage I’ve got all the data I want, so I can begin building the itinerary. I’ve calculated all possible city/date combination of flights. Job interviews questions prepared me for that:

next_flight_origin_city = dict ( zip ( places_df . city . iloc [: - 2 ], places_df . city . iloc [ 1 : - 1 ])) place_min_days = dict ( zip ( places_df . city . iloc [: - 1 ], places_df . min_days . iloc [: - 1 ])) place_max_days = dict ( zip ( places_df . city . iloc [: - 1 ], places_df . max_days . iloc [: - 1 ])) def build_itinerary ( place , date ): if place is None : return next_place = next_flight_origin_city . get ( place ) for days in range ( place_min_days [ place ], place_max_days [ place ] + 1 ): flight_date = date + timedelta ( days = days ) for rest_flights in build_itinerary ( next_place , flight_date ): yield [( place , flight_date ), * rest_flights ] if next_place is None : yield [( place , flight_date )] itinerary = [ * build_itinerary ( 'Amsterdam' , min_start )] itinerary [: 3 ]

[[( 'Amsterdam' , datetime . date ( 2019 , 7 , 10 )), ( 'Moscow' , datetime . date ( 2019 , 7 , 13 )), ( 'Irkutsk' , datetime . date ( 2019 , 7 , 20 )), ( 'Beijing' , datetime . date ( 2019 , 7 , 23 )), ( 'Shanghai' , datetime . date ( 2019 , 7 , 26 )), ( 'Tokyo' , datetime . date ( 2019 , 7 , 29 ))], [( 'Amsterdam' , datetime . date ( 2019 , 7 , 10 )), ( 'Moscow' , datetime . date ( 2019 , 7 , 13 )), ( 'Irkutsk' , datetime . date ( 2019 , 7 , 20 )), ( 'Beijing' , datetime . date ( 2019 , 7 , 23 )), ( 'Shanghai' , datetime . date ( 2019 , 7 , 26 )), ( 'Tokyo' , datetime . date ( 2019 , 7 , 30 ))], [( 'Amsterdam' , datetime . date ( 2019 , 7 , 10 )), ( 'Moscow' , datetime . date ( 2019 , 7 , 13 )), ( 'Irkutsk' , datetime . date ( 2019 , 7 , 20 )), ( 'Beijing' , datetime . date ( 2019 , 7 , 23 )), ( 'Shanghai' , datetime . date ( 2019 , 7 , 26 )), ( 'Tokyo' , datetime . date ( 2019 , 7 , 31 ))]]

And then I’ve found all flights for those dates. As amount of possible flights combinations didn’t fit in my RAM, I was selecting n_cheapest flights on each stage. The code is slow and ugly, but it worked:

def find_flights ( prices_with_city_df , itinerary_route , n_cheapest ): result_df = None for place , date in itinerary_route : place_df = prices_with_city_df \ [( prices_with_city_df . origin_city == place ) & ( prices_with_city_df . date == date )] \ . sort_values ( 'price' , ascending = True ) \ . head ( n_cheapest ) \ . add_prefix ( f' { place } _' ) if result_df is None : result_df = place_df else : result_df = result_df \ . assign ( key = 1 ) \ . merge ( place_df . assign ( key = 1 ), on = "key" ) \ . drop ( "key" , axis = 1 ) result_df [ 'total_price' ] = reduce ( operator . add , ( result_df [ column ] for column in result_df . columns if 'price' in column and column != 'total_price' )) result_df = result_df \ . sort_values ( 'total_price' , ascending = True ) \ . head ( n_cheapest ) result_df [ 'total_flights_duration' ] = reduce ( operator . add , ( result_df [ column ] for column in result_df . columns if 'duration' in column )) return result_df [[ 'total_price' , 'total_flights_duration' ] + [ column for column in result_df . columns if 'total_' not in column ]] find_flights ( prices_with_city_df , itinerary [ 0 ], 100 ). head ( 5 )

total_price total_flights_duration Amsterdam_origin Amsterdam_destination Amsterdam_date Amsterdam_price Amsterdam_departure_at Amsterdam_arrival_at Amsterdam_segments Amsterdam_duration Amsterdam_origin_city Amsterdam_destination_city Amsterdam_route Moscow_origin Moscow_destination Moscow_date Moscow_price Moscow_departure_at Moscow_arrival_at Moscow_segments Moscow_duration Moscow_origin_city Moscow_destination_city Moscow_route Irkutsk_origin Irkutsk_destination Irkutsk_date Irkutsk_price Irkutsk_departure_at Irkutsk_arrival_at Irkutsk_segments Irkutsk_duration Irkutsk_origin_city Irkutsk_destination_city Irkutsk_route Beijing_origin Beijing_destination Beijing_date Beijing_price Beijing_departure_at Beijing_arrival_at Beijing_segments Beijing_duration Beijing_origin_city Beijing_destination_city Beijing_route Shanghai_origin Shanghai_destination Shanghai_date Shanghai_price Shanghai_departure_at Shanghai_arrival_at Shanghai_segments Shanghai_duration Shanghai_origin_city Shanghai_destination_city Shanghai_route Tokyo_origin Tokyo_destination Tokyo_date Tokyo_price Tokyo_departure_at Tokyo_arrival_at Tokyo_segments Tokyo_duration Tokyo_origin_city Tokyo_destination_city Tokyo_route 0 1901.41 1 days 20:45:00 AMS SVO 2019-07-10 203.07 2019-07-10 21:15:00+02:00 2019-07-11 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-13 227.40 2019-07-13 18:30:00+03:00 2019-07-14 05:15:00+08:00 1 05:45:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-20 209.11 2019-07-20 01:50:00+08:00 2019-07-20 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-23 171.64 2019-07-23 11:30:00+08:00 2019-07-23 14:00:00+08:00 1 02:30:00 Beijing Shanghai Beijing ✈️ Shanghai SHA NRT 2019-07-26 394.07 2019-07-26 14:35:00+08:00 2019-07-26 18:15:00+09:00 1 02:40:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-29 696.12 2019-07-29 17:55:00+09:00 2019-07-30 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 2800 1901.41 1 days 20:30:00 AMS SVO 2019-07-10 203.07 2019-07-10 11:50:00+02:00 2019-07-10 16:05:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-13 227.40 2019-07-13 18:30:00+03:00 2019-07-14 05:15:00+08:00 1 05:45:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-20 209.11 2019-07-20 01:50:00+08:00 2019-07-20 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-23 171.64 2019-07-23 21:30:00+08:00 2019-07-23 23:45:00+08:00 1 02:15:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-26 394.07 2019-07-26 14:35:00+08:00 2019-07-26 18:15:00+09:00 1 02:40:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-29 696.12 2019-07-29 17:55:00+09:00 2019-07-30 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 2900 1901.41 1 days 20:30:00 AMS SVO 2019-07-10 203.07 2019-07-10 21:15:00+02:00 2019-07-11 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-13 227.40 2019-07-13 18:30:00+03:00 2019-07-14 05:15:00+08:00 1 05:45:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-20 209.11 2019-07-20 01:50:00+08:00 2019-07-20 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-23 171.64 2019-07-23 10:00:00+08:00 2019-07-23 12:15:00+08:00 1 02:15:00 Beijing Shanghai Beijing ✈️ Shanghai SHA NRT 2019-07-26 394.07 2019-07-26 14:35:00+08:00 2019-07-26 18:15:00+09:00 1 02:40:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-29 696.12 2019-07-29 17:55:00+09:00 2019-07-30 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 3000 1901.41 1 days 20:30:00 AMS SVO 2019-07-10 203.07 2019-07-10 21:15:00+02:00 2019-07-11 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-13 227.40 2019-07-13 18:30:00+03:00 2019-07-14 05:15:00+08:00 1 05:45:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-20 209.11 2019-07-20 01:50:00+08:00 2019-07-20 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-23 171.64 2019-07-23 10:00:00+08:00 2019-07-23 12:15:00+08:00 1 02:15:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-26 394.07 2019-07-26 14:35:00+08:00 2019-07-26 18:15:00+09:00 1 02:40:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-29 696.12 2019-07-29 17:55:00+09:00 2019-07-30 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 3100 1901.41 1 days 20:30:00 AMS SVO 2019-07-10 203.07 2019-07-10 21:15:00+02:00 2019-07-11 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-13 227.40 2019-07-13 18:30:00+03:00 2019-07-14 05:15:00+08:00 1 05:45:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-20 209.11 2019-07-20 01:50:00+08:00 2019-07-20 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-23 171.64 2019-07-23 17:00:00+08:00 2019-07-23 19:15:00+08:00 1 02:15:00 Beijing Shanghai Beijing ✈️ Shanghai SHA NRT 2019-07-26 394.07 2019-07-26 14:35:00+08:00 2019-07-26 18:15:00+09:00 1 02:40:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-29 696.12 2019-07-29 17:55:00+09:00 2019-07-30 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam

So now it’s easy to get the cheapest flights by calling the function for all possible itineraries:

itinerary_df = reduce ( pd . DataFrame . append , ( find_flights ( prices_with_city_df , itinerary_route , 10 ) for itinerary_route in itinerary )) itinerary_df \ . sort_values ([ 'total_price' , 'total_flights_duration' ]) \ . head ( 10 )

total_price total_flights_duration Amsterdam_origin Amsterdam_destination Amsterdam_date Amsterdam_price Amsterdam_departure_at Amsterdam_arrival_at Amsterdam_segments Amsterdam_duration Amsterdam_origin_city Amsterdam_destination_city Amsterdam_route Moscow_origin Moscow_destination Moscow_date Moscow_price Moscow_departure_at Moscow_arrival_at Moscow_segments Moscow_duration Moscow_origin_city Moscow_destination_city Moscow_route Irkutsk_origin Irkutsk_destination Irkutsk_date Irkutsk_price Irkutsk_departure_at Irkutsk_arrival_at Irkutsk_segments Irkutsk_duration Irkutsk_origin_city Irkutsk_destination_city Irkutsk_route Beijing_origin Beijing_destination Beijing_date Beijing_price Beijing_departure_at Beijing_arrival_at Beijing_segments Beijing_duration Beijing_origin_city Beijing_destination_city Beijing_route Shanghai_origin Shanghai_destination Shanghai_date Shanghai_price Shanghai_departure_at Shanghai_arrival_at Shanghai_segments Shanghai_duration Shanghai_origin_city Shanghai_destination_city Shanghai_route Tokyo_origin Tokyo_destination Tokyo_date Tokyo_price Tokyo_departure_at Tokyo_arrival_at Tokyo_segments Tokyo_duration Tokyo_origin_city Tokyo_destination_city Tokyo_route 10 1817.04 1 days 19:50:00 AMS SVO 2019-07-11 203.07 2019-07-11 21:15:00+02:00 2019-07-12 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 21:50:00+08:00 2019-07-25 23:55:00+08:00 1 02:05:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 40 1817.04 1 days 19:50:00 AMS SVO 2019-07-11 203.07 2019-07-11 21:15:00+02:00 2019-07-12 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 21:50:00+08:00 2019-07-25 23:55:00+08:00 1 02:05:00 Beijing Shanghai Beijing ✈️ Shanghai SHA NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 0 1817.04 1 days 20:00:00 AMS SVO 2019-07-10 203.07 2019-07-10 21:15:00+02:00 2019-07-11 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 13:00:00+08:00 2019-07-25 15:15:00+08:00 1 02:15:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 70 1817.04 1 days 20:00:00 AMS SVO 2019-07-10 203.07 2019-07-10 11:50:00+02:00 2019-07-10 16:05:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 18:00:00+08:00 2019-07-25 20:15:00+08:00 1 02:15:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 60 1817.04 1 days 20:00:00 AMS SVO 2019-07-10 203.07 2019-07-10 11:50:00+02:00 2019-07-10 16:05:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 13:00:00+08:00 2019-07-25 15:15:00+08:00 1 02:15:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 0 1817.04 1 days 20:00:00 AMS SVO 2019-07-11 203.07 2019-07-11 21:15:00+02:00 2019-07-12 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 13:00:00+08:00 2019-07-25 15:15:00+08:00 1 02:15:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 10 1817.04 1 days 20:05:00 AMS SVO 2019-07-10 203.07 2019-07-10 11:50:00+02:00 2019-07-10 16:05:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 12:00:00+08:00 2019-07-25 14:20:00+08:00 1 02:20:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 40 1817.04 1 days 20:05:00 AMS SVO 2019-07-10 203.07 2019-07-10 11:50:00+02:00 2019-07-10 16:05:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 12:00:00+08:00 2019-07-25 14:20:00+08:00 1 02:20:00 Beijing Shanghai Beijing ✈️ Shanghai SHA NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 70 1817.04 1 days 20:05:00 AMS SVO 2019-07-11 203.07 2019-07-11 21:15:00+02:00 2019-07-12 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 18:30:00+08:00 2019-07-25 20:50:00+08:00 1 02:20:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam 60 1817.04 1 days 20:05:00 AMS SVO 2019-07-11 203.07 2019-07-11 21:15:00+02:00 2019-07-12 01:30:00+03:00 1 03:15:00 Amsterdam Moscow Amsterdam ✈️ Moscow DME IKT 2019-07-15 198.03 2019-07-15 18:35:00+03:00 2019-07-16 05:05:00+08:00 1 05:30:00 Moscow Irkutsk Moscow ✈️ Irkutsk IKT PEK 2019-07-22 154.11 2019-07-22 01:50:00+08:00 2019-07-22 04:40:00+08:00 1 02:50:00 Irkutsk Beijing Irkutsk ✈️ Beijing PEK SHA 2019-07-25 171.64 2019-07-25 11:00:00+08:00 2019-07-25 13:20:00+08:00 1 02:20:00 Beijing Shanghai Beijing ✈️ Shanghai PVG NRT 2019-07-28 394.07 2019-07-28 17:15:00+08:00 2019-07-28 20:40:00+09:00 1 02:25:00 Shanghai Tokyo Shanghai ✈️ Tokyo NRT AMS 2019-07-31 696.12 2019-07-31 17:55:00+09:00 2019-08-01 14:40:00+02:00 2 1 days 03:45:00 Tokyo Amsterdam Tokyo ✈️ Amsterdam

Conclusion

I was able to find the cheapest flights with the minimal duration and the resulting prices were almost the same as on Google Flights.

As a side-note I’ll probably reconsider my trip.

Links: