Skip to content

Instantly share code, notes, and snippets.

@dag10
Last active November 20, 2017 09:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dag10/f4c15381ee88c4870f0edc075b0cf8f0 to your computer and use it in GitHub Desktop.
Save dag10/f4c15381ee88c4870f0edc075b0cf8f0 to your computer and use it in GitHub Desktop.
A script with instructions for scraping your flight history from Google Inbox and mapping them.

Google Inbox Flight Scraper

First, go here: https://inbox.google.com/u/0/trips

Keep scrolling to the bottom until no more trips load.

Then open the developer console and paste the code below. Leave it alone for a few minutes. Once it's done scraping your flights, click the link it prints to the end of the console. This will take you to gcmap.com, which will then ask you to disambiguate the city names (e.g. "Washington DC") to IATA airport codes (e.g. "IAD").

Once you've disambiguated all airport codes, it'll show you your flight history map. You can copy the URL to share it.

Important caveat: Inbox doesn't display airport codes, only city names. This is what's sent to gcmap.com, which asks you to disambiguate city names to airport codes. However, it will turn all instances of that city name to the airport. So let's say you've flow into both LGW and LHR. Once you disambiguate "London" to "LHR", it'll assume all London flights were LHR. For this reason, I told gcmap.com to not print the airport codes on the map (the ?PM=- in the URL).

var maxTrips = 9999;

// Have some flights in your Google Inbox that you want this script to ignore?
// Put their details in here. Below are four flights I was once going to take
// before I changed my itinerary, but I can't seem to make Google forget them.
var ignoreFlights = [
    {
        from: 'Newark',
        to: 'Beijing',
        date: new Date('Jan 6, 2015'),
    },
    {
        from: 'Beijing',
        to: 'Hong Kong',
        date: new Date('Jan 10, 2015'),
    },
    {
        from: 'Hong Kong',
        to: 'Chicago',
        date: new Date('Jan 22, 2015'),
    },
    {
        from: 'Chicago',
        to: 'Tampa',
        date: new Date('Jan 22, 2015'),
    },
];

(async function() {
    var trips = document.getElementsByClassName("an aT");
    var tripAnimTime = 1000;
    var tripDetailAnimTime = 100;

    async function wait(time) {
        return new Promise((resolve, reject) => setTimeout(resolve, time));
    }

    async function expandTrip(i) {
        try {
            trips[i].click();
            await wait(tripAnimTime);
        } catch(e) {}
    }

    async function collapseTrip() {
        try {
            document.getElementsByClassName("ob")[0].click();
            await wait(tripAnimTime);
        } catch(e) {}
    }

    async function expandTripDetail(i) {
        try {
            document.getElementsByClassName("G4 an")[i].click();
            await wait(tripDetailAnimTime);
        } catch(e) {}
    }

    async function collapseTripDetail() {
        try {
            document.getElementsByClassName("hM")[0].click();
            await wait(tripDetailAnimTime);
        } catch(e) {}
    }

    function scrapeOpenedTripDetail() {
        var subtitle = document.getElementsByClassName("oy");
        if (subtitle.length > 0 && subtitle[0].innerText.toLowerCase().indexOf("flight") >= 0) {
            var title = document.getElementsByClassName("nM")[0].firstChild.innerText;
            var from = title.split(" to ")[0];
            var to = title.split(" to ")[1];
            var date = new Date(document.getElementsByClassName("rP on")[0].firstChild.innerText);
            if (date.getFullYear() < 2013) {
                date.setFullYear(new Date(Date.now()).getFullYear());
            }
            return {
                from: from,
                to: to,
                date: date,
            }
        }
        return null;
    }

    function shouldIgnoreFlight(detail) {
        for (var k = 0; k < ignoreFlights.length; k++) {
            if (detail.from != ignoreFlights[k].from) continue;
            if (detail.to != ignoreFlights[k].to) continue;
            if (detail.date.toString() != ignoreFlights[k].date.toString()) continue;
            return true;    
        }
        return false;
    }

    var flights = []

    await collapseTrip();

    for (var i = 0; i < trips.length && i < maxTrips; i++) {
        await expandTrip(i);

        var tripDetails = document.getElementsByClassName("G4 an");
        var flightDetails = [];
        
        for (var j = 0; j < tripDetails.length; j++) {
            await expandTripDetail(j);
            var detail = scrapeOpenedTripDetail();
            if (detail && !shouldIgnoreFlight(detail)) {
                flightDetails.push(detail);
            }
            await collapseTripDetail();
        }

        // Reverse the order of flights in a trip to maintain chonological order of all flights in the end.
        while (flightDetails.length > 0) {
            var detail = flightDetails.pop();
            console.info("Found flight:", detail);
            flights.push(detail);
        }

        await collapseTrip();
    }
    
    var gcmap = "http://www.gcmap.com/mapui?PM=-&P=";
    for (var i = 0; i < flights.length; i++) {
        if (i > 0) gcmap += ",";
        gcmap += (flights[i].from.replace(",", "") + "-" + flights[i].to.replace(",", ""))
            .replace(/\s/g, '+')
            .normalize('NFD')
            .replace(/[\u0300-\u036f]/g, ""); // Remove accents.
    }

    console.info("Flights:", flights);
    console.info("Click here for map:", gcmap);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment