How to Scrape Google Flights & Airfare Data with Python in 2026
Step-by-step Python tutorial on scraping Google Flights airfare prices, schedules, and routes using Playwright and rotating residential proxies in 2026.

Step-by-step Python tutorial on scraping Google Flights airfare prices, schedules, and routes using Playwright and rotating residential proxies in 2026.
Google Flights is a popular service for finding and booking flights, providing a vast amount of data like prices, schedules, and airline details. While Google doesn't offer a public API for this data, web scraping is an effective alternative. This post will guide you through creating a robust Google Flights scraper using Python, and show how ProxyTee can enhance your scraping efforts.
Why Scrape Google Flights?
Scraping Google Flights offers several advantages:
- Track flight prices over time: Monitor price changes to identify the best deals.
- Analyze price trends: Understand market dynamics to make informed booking decisions.
- Identify the best times to book: Find optimal booking times to secure lower fares.
- Compare prices: Easily compare prices across different dates and airlines.
This data is invaluable for both travelers seeking the best deals and businesses performing market analysis, competitor tracking, and pricing strategy development. By using ProxyTee's Unlimited Residential Proxies, you can efficiently gather this data while minimizing the risk of IP blocks.
Building a Google Flights Scraper with ProxyTee
Our scraper will allow you to input the departure airport, destination, travel date, and ticket type (one-way or round-trip). For round trips, you'll also specify a return date. The scraper fetches available flights, extracts the relevant data, and saves it into a JSON file for further analysis. ProxyTee's unlimited bandwidth ensures your data-intensive tasks won't face interruptions.
1. Data You Can Extract
The scraper extracts crucial information, such as:
- Airline names
- Departure and arrival times
- Flight duration
- Number of stops
- Ticket prices
- Environmental impact data (CO2 emissions)
Here’s an example of the scraped data:
{
"airline": "Alaska",
"departure_time": "5:22 PM",
"arrival_time": "9:13 PM",
"duration": "6 hr 51 min",
"stops": "Nonstop",
"price": "₹51,984",
"co2_emissions": "282 kg CO2e",
"emissions_variation": "-22% emissions"
}
2. Setting Up the Environment
To set up your environment, follow these steps:
# Create a virtual environment (optional)
python -m venv flight-scraper-env
# Activate the virtual environment
# On Windows:
.\flight-scraper-env\Scripts\activate
# On macOS/Linux:
source flight-scraper-env/bin/activate
# Install required packages
pip install playwright tenacity asyncio
# Install Playwright browsers
playwright install chromium
We’ll use ProxyTee's residential proxies combined with Playwright for browser automation and Tenacity for retries.
3. Defining Data Classes
Use Python's dataclass for data structuring:
from dataclasses import dataclass
from typing import Optional
@dataclass
class SearchParameters:
departure: str
destination: str
departure_date: str
return_date: Optional[str] = None
ticket_type: str = "One way"
@dataclass
class FlightData:
airline: str
departure_time: str
arrival_time: str
duration: str
stops: str
price: str
co2_emissions: str
emissions_variation: str
SearchParameters stores flight search details, while FlightData stores data about each flight.
4. Scraper Logic in the FlightScraper Class
The core logic is within the FlightScraper class:
4.1 Defining CSS Selectors
class FlightScraper:
SELECTORS = {
"airline": "div.sSHqwe.tPgKwe.ogfYpf",
"departure_time": 'span[aria-label^="Departure time"]',
"arrival_time": 'span[aria-label^="Arrival time"]',
"duration": 'div[aria-label^="Total duration"]',
"stops": "div.hF6lYb span.rGRiKd",
"price": "div.FpEdX span",
"co2_emissions": "div.O7CXue",
"emissions_variation": "div.N6PNV",
}
These CSS selectors pinpoint specific data elements on Google Flights pages.
4.2 Filling the Search Form
The _fill_search_form method automates the form filling using parameters like the departure city, destination, and travel date:
async def _fill_search_form(self, page, params: SearchParameters) -> None:
# First, let's pick our ticket type
ticket_type_div = page.locator("div.VfPpkd-TkwUic[jsname='oYxtQd']").first
await ticket_type_div.click()
await page.wait_for_selector("ul[aria-label='Select your ticket type.']")
await page.locator("li").filter(has_text=params.ticket_type).nth(0).click()
# Now, let's fill in our departure and destination
from_input = page.locator("input[aria-label='Where from?']")
await from_input.click()
await from_input.fill("")
await page.keyboard.type(params.departure)
# ... rest of the form filling code
4.3 Loading All Results
Use the _load_all_flights method to scroll through pagination of Google Flights to ensure we capture all available flights:
async def _load_all_flights(self, page) -> None:
while True:
try:
more_button = await page.wait_for_selector(
'button[aria-label*="more flights"]', timeout=5000
)
if more_button:
await more_button.click()
await page.wait_for_timeout(2000)
else:
break
except:
break
4.4 Extracting Flight Data
The method _extract_flight_data uses the CSS selectors to scrape data from the webpage after all the flights are loaded:
async def _extract_flight_data(self, page) -> List[FlightData]:
await page.wait_for_selector("li.pIav2d", timeout=30000)
await self._load_all_flights(page)
flights = await page.query_selector_all("li.pIav2d")
flights_data = []
for flight in flights:
flight_info = {}
for key, selector in self.SELECTORS.items():
element = await flight.query_selector(selector)
flight_info[key] = await self._extract_text(element)
flights_data.append(FlightData(**flight_info))
return flights_data
5. Adding a Retry Mechanism
Use Tenacity for reliability:
@retry(stop=stop_after_attempt(3), wait=wait_fixed(5))
async def search_flights(self, params: SearchParameters) -> List[FlightData]:
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
context = await browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
)
# ... rest of the search implementation
6. Saving Scraped Results
Save the data to a JSON file using:
def save_results(self, flights: List[FlightData], params: SearchParameters) -> str:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = (
f"flight_results_{params.departure}_{params.destination}_{timestamp}.json"
)
output_data = {
"search_parameters": {
"departure": params.departure,
"destination": params.destination,
"departure_date": params.departure_date,
"return_date": params.return_date,
"search_timestamp": timestamp,
},
"flights": [vars(flight) for flight in flights],
}
filepath = os.path.join(self.results_dir, filename)
with open(filepath, "w", encoding="utf-8") as f:
json.dump(output_data, f, indent=2, ensure_ascii=False)
return filepath
7. Running the Scraper
async def main():
scraper = FlightScraper()
params = SearchParameters(
departure="MIA",
destination="SEA",
departure_date="2025-12-01",
# return_date="2025-12-30",
ticket_type="One way",
)
try:
flights = await scraper.search_flights(params)
print(f"Successfully found {len(flights)} flights")
except Exception as e:
print(f"Error during flight search: {str(e)}")
if __name__ == "__main__":
asyncio.run(main())
Final Results
After running the scraper, flight data is saved in a JSON file:
{
"search_parameters": {
"departure": "MIA",
"destination": "SEA",
"departure_date": "2025-12-01",
"return_date": null,
"search_timestamp": "20251027_172017"
},
"flights": [
{
"airline": "American",
"departure_time": "7:45 PM",
"arrival_time": "11:38 PM",
"duration": "6 hr 53 min",
"stops": "Nonstop",
"price": "₹50,755",
"co2_emissions": "303 kg CO2e",
"emissions_variation": "-16% emissions"
},
{
"airline": "Alaska",
"departure_time": "5:22 PM",
"arrival_time": "9:13 PM",
"duration": "6 hr 51 min",
"stops": "Nonstop",
"price": "₹51,984",
"co2_emissions": "282 kg CO2e",
"emissions_variation": "-22% emissions"
},
{
"airline": "Alaska",
"departure_time": "9:00 AM",
"arrival_time": "12:40 PM",
"duration": "6 hr 40 min",
"stops": "Nonstop",
"price": "₹62,917",
"co2_emissions": "325 kg CO2e",
"emissions_variation": "-10% emissions"
}
]
}
Common Challenges in Google Flights Scraping
Challenges such as IP blocking and CAPTCHAs are common when scaling Google Flights scraping. Using ProxyTee’s residential proxies, you can significantly reduce these issues by rotating through numerous IP addresses, making your requests look like organic traffic and not automated bots. ProxyTee's auto-rotation feature makes this process smooth, and the diverse IPs in the global IP pool means you will avoid getting blocked by target website.
The Solution: ProxyTee's Powerful Tools
ProxyTee offers tools designed to simplify and enhance your web scraping efforts effectively.
1. Residential Proxies
ProxyTee’s residential proxies enable scraping requests to go through legitimate residential connections, so they appear as real users to the target website and you can easily scrape data without facing blocks. This feature is great for dealing with anti-scraping measures used by sites like Google Flights.
2. Unlimited Bandwidth
ProxyTee provides proxies with unlimited bandwidth, eliminating worries about overages. This allows you to conduct data-intensive web scraping or streaming without incurring extra charges, making ProxyTee a cost-effective and scalable solution.
3. Auto Rotation
ProxyTee's auto-rotation changes IP addresses at customized intervals between 3 to 60 minutes. This is particularly valuable in web scraping to help avoid being detected and banned from target websites. ProxyTee offers not only rotation feature, but it can target specific locations using geo/country targeting rather than random IPs or limited options like our competitors. You have the options to choose proxies you really want based on your needs.
4. Easy Integration and Simple API
ProxyTee prioritizes usability with a clean interface which makes it easy for anyone, including non-technical users, to set up and use our products quickly. Besides, ProxyTee offers a simple API that integrates into different application and workflows smoothly, perfect for automation. This combination helps ensure smooth data scraping experiences with great values compared to competitors. ProxyTee also provides supports of both HTTP and SOCKS5 protocols, allowing seamless compatibility and use with various applications.
Conclusion
This article explored how to scrape Google Flights data using Python and Playwright. Although manual scraping can be efficient, challenges like IP bans often need more robust solutions. To simplify data collection and improve efficiency, using ProxyTee is highly recommended because we have Unlimited Residential Proxies with unlimited bandwidth, diverse IP pools, smooth rotation, simple to use and low price. Take a look our pricing to start experience the different.

Why Travel Fare Aggregation Requires Geo-Targeted Residential Proxies
Airlines, OTAs, and meta-search engines like Google Flights dynamically adjust ticket availability, currency, and fare classes based on the visitor's point-of-sale IP location and browser session history. Building a reliable proxy for travel fare aggregation requires three capabilities:
- Multi-Country Point-of-Sale Accuracy: Route your flight scrapers through US Residential Proxies, UK Residential Proxies, Canada Residential Proxies, or Germany Residential Proxies to compare localized airfare pricing across 100+ markets.
- Unmetered Bandwidth for Heavy Headless DOMs: Each Playwright or Selenium flight search loads several megabytes of JavaScript bundles and route matrices. ProxyTee's unlimited bandwidth ports let you poll thousands of origin-destination pairs 24/7 with zero per-GB overage charges.
- Sticky & Rotating Sessions (3–60m): Maintain a sticky residential IP while paginating return-flight combinations, then rotate cleanly via Auto Rotation.
Complete Your Travel Data Scraping Pipeline with ProxyTee
Combine airfare extraction with hotel and hospitality intelligence by exploring our Travel Fare Aggregation Proxies, Booking.com & Airbnb Proxies, and step-by-step tutorials on How to Scrape Hotels from Google Travel and How to Scrape TripAdvisor Hotel Data.
Recommended ProxyTee Configuration & Bandwidth Benchmark
To run How to Scrape Google Flights & Airfare Data with Python in 2026 reliably in production without per-gigabyte overage fees, pair ProxyTee Unlimited Residential Proxies with our BitBrowser Integration Guide and Travel Fare Aggregation workflow. You can route traffic through localized household ISPs such as United Arab Emirates Residential Proxies (690,000+ IPs) or compare flat-rate port economics in our ProxyTee vs. NetNut benchmark.
Recommended ProxyTee Configuration for Tutorial
When deploying this workflow in production, matching your protocol, rotation interval, and concurrency tier to the target anti-bot posture is critical. Compare the recommended configurations below:
| Configuration Parameter | High-Throughput Scraping | Stateful Session / Multi-Account | ProxyTee Advantage |
|---|---|---|---|
| Proxy Protocol | HTTP / HTTPS or SOCKS5h | SOCKS5 with Remote DNS | Dual protocol support on every port |
| Rotation Interval | 3 to 10 minutes auto-rotation | 30 to 60 minutes sticky window | Configurable 3–60m in GUI & REST API |
| Authentication | IP Whitelisting (Server / Docker) | Username:Password per profile | Dual auth modes included free |
| Bandwidth Billing | 100% Unmetered ($0.00/GB) | 100% Unmetered ($0.00/GB) | Saves up to 95% vs metered per-GB providers |
Frequently Asked Questions
Google Flights and airline booking engines block datacenter ASNs and display different ticket prices depending on the user's country IP. Using ProxyTee's residential proxies for travel fare aggregation lets you extract accurate, unblocked airfare data across 100+ countries.
Principal infrastructure engineer at ProxyTee specializing in rotating residential proxy networks, SOCKS5/HTTP tunneling, TLS fingerprint mitigation, and distributed data extraction pipelines.


