Jak scrapovat Google Flights v Pythonu: od kódu k upozorněním na cenu

Naposledy aktualizováno August 20, 2026
Jak scrapovat Google Flights v Pythonu: od kódu k upozorněním na cenu

Google ukončil své Flights API už v roce 2018, ale ceny letenek se dál mění — u jedné domácí trasy až 17krát za 48 hodin. Pokud k těmto datům chcete přistupovat programově, scraping je v podstatě jediná reálná cesta.

Strávil jsem hodně času testováním různých přístupů k získávání letových dat z Googlu a situace se zásadně změnila — zejména poté, co Google v lednu 2025 nasadil SearchGuard. V tomto návodu vám ukážu, jak postavit funkční Python scraper pro Google Flights pomocí Playwrightu, jak zvládnout anti-bot opatření, na kterých většina lidí ztroskotá, a pak z toho vytvořit automatický sledovač cen s upozorněními. Pokud se chcete obejít bez kódu, ukážu také no-code zkratku přes Thunderbit, se kterou se dostanete ke stejnému výsledku přibližně za dvě minuty.

Proč scrapovat Google Flights v Pythonu?

Google Flights dominuje vyhledávání letenek. Jeho viditelnost na mobilech v USA vyskočila na 47,6 %, čímž předstihl všechny hlavní OTA platformy. Trh cestovních metavyhledávačů má hodnotu $8,33 miliardy v roce 2024 a roste tempem 30,2 % CAGR. Jenže od chvíle, kdy bylo QPX Express API trvale vypnuto 10. dubna 2018, neexistuje oficiální způsob, jak se k těmto datům dostat programově.

Mezitím se ceny letenek u stejné itineráře mohou měnit až o 50 %, přičemž rozdíl mezi nejnižší a nejvyšší cenou bývá v průměru kolem 20 dolarů. Letecké společnosti jako Delta používají pro dynamické naceňování 77 cenových kategorií. Průměrná zpáteční letenka v USA na začátku roku 2026 stojí 408 dolarů a letenky jsou meziročně o 14,9 % dražší.

Dominantní platforma, žádné API, proměnlivé ceny. Proto se scraping Google Flights v Pythonu stal jedním z nejčastějších projektů na GitHubu i v cestovatelských fórech.

Tohle z něj mohou těžit a jak:

Typ uživatelePřípad použitíHlavní přínos
Jednotliví cestujícíSledování cen konkrétních tras v časeÚspora v průměru $50 na let
Cestovní agenturyCenová inteligence vůči konkurenciMonitoring parity cen v reálném čase
Firemní travel týmyOptimalizace nákladů napříč trasamiÚspora 10–30 % na služebních cestách
VývojářiTvorba aplikací pro porovnání tarifůProgramový přístup k cenovým datům
VýzkumníciAnalýza cenové volatility aerolinekAkademický a tržní výzkum

Uživatelé ve fórech to říkají naplno: „Google Flights API bylo zrušeno a měl bych místo toho použít web scraping“ je názor, který se objevuje znovu a znovu. A návratnost je reálná — Hopper tvrdí 95% přesnost predikcí při analýze více než 5 miliard cenových nabídek denně, zatímco data Expedia z roku 2026 ukazují, že rezervace 8–15 dní před odletem ušetří asi 25 dolarů na domácích letech.

Jaká data lze z Google Flights scrapovat?

Výsledková stránka Google Flights obsahuje překvapivě bohatou sadu dat. Typicky lze získat:

  • Název aerolinky (a logo)
  • Čas odletu a kód letiště
  • Čas příletu a kód letiště
  • Celkovou dobu letu
  • Počet přestupů a detaily přestupů (letiště, délka, zda jde o noční přestup)
  • Cenu letenky (podle měny)
  • Emise CO2 (kg CO2e, včetně procentního rozdílu oproti běžným letům)
  • Cestovní třídu, číslo letu, model letadla
  • Prostor pro nohy
  • Doplňky (Wi‑Fi, zásuvky, streamování médií)
  • Ukazatel cenové úrovně (nízká / běžná / vysoká)
  • Varování před zpožděním („Často zpožděno o více než 30 min“)

Dostupnost dat se liší podle trasy, data a typu letenky (jednosměrná vs. zpáteční). Takhle vypadá jeden scrapovaný záznam letu ve formátu JSON:

{
  "search_date": "2026-04-16",
  "route": "SFO-JFK",
  "departure_date": "2026-05-15",
  "flights": [
    {
      "airline": "United Airlines",
      "flight_number": "UA123",
      "departure_time": "08:00",
      "departure_airport": "SFO",
      "arrival_time": "16:35",
      "arrival_airport": "JFK",
      "duration_minutes": 335,
      "stops": 0,
      "price_usd": 287,
      "price_level": "low",
      "co2_kg": 156,
      "co2_vs_typical": "-12%",
      "travel_class": "Economy"
    }
  ]
}

Nastavení Python prostředí

Než napíšeme první scrapingový kód, je potřeba mít připraveno několik věcí.

Požadavky:

  • Obtížnost: Střední
  • Časová náročnost: cca 1–2 hodiny pro celý tutoriál
  • Co budete potřebovat: Python 3.7+, základní znalost Pythonu, prohlížeč založený na Chromiu

Instalace potřebných knihoven

Použijeme Playwright pro automatizaci prohlížeče (Google Flights je z 100 % renderovaný JavaScriptem — běžné HTTP požadavky vrací jen nepoužitelný obsah), plus několik pomocníků:

pip install playwright playwright-stealth pandas
playwright install chromium
  • Playwright — automatizace headless prohlížeče, zvládá renderování JavaScriptu, vestavěné čekací mechanismy
  • playwright-stealth — maskuje běžné signály detekce botů
  • pandas — pro analýzu dat a pozdější export do CSV

Proč Playwright místo Selenium nebo requests

Google Flights nebude fungovat jen s requests + BeautifulSoup — obsah stránky se vykresluje výhradně pomocí JavaScriptu. Potřebujete skutečný prohlížeč.

VlastnostPlaywrightSeleniumrequests + BS4
Renderování JSPlná podporaPlná podporaŽádné
RychlostO 42 % rychlejší celkověZákladV tomto případě N/A
Podpora asyncNativníJen sekvenčněN/A
Využití pamětiO 30 % méněVyššíMinimální
Obejití detekce botůDobré (se stealth režimem)Snáz detekovatelnéN/A

Playwright je rychlejší, modernější a lépe zvládá async. Pro Google Flights je to jasná volba.

Krok za krokem: Jak scrapovat Google Flights v Pythonu

Tohle je jádro celého návodu. Scraper postavíme postupně.

google-flights-scraping-workflow.webp

Krok 1: Definujte datové třídy

Začněte tím, že si v Pythonu pomocí dataclassů strukturovaně popíšete parametry vyhledávání a data o letech. Kód bude čistší a později se bude lépe rozšiřovat.

from dataclasses import dataclass, field
from typing import Optional, List

@dataclass
class SearchParams:
    origin: str          # např. "SFO"
    destination: str     # např. "JFK"
    departure_date: str   # např. "2026-05-15"
    return_date: Optional[str] = None
    trip_type: str = "one-way"  # "one-way" nebo "round-trip"
    travel_class: str = "economy"

@dataclass
class FlightData:
    airline: str = ""
    departure_time: str = ""
    arrival_time: str = ""
    duration: str = ""
    stops: str = ""
    price: str = ""
    co2_emissions: str = ""

Každé pole přímo odpovídá tomu, co budeme ze stránky extrahovat. Díky této struktuře nebudete později předávat nepořádné slovníky.

Krok 2: Pochopení struktury URL Google Flights

Google Flights kódování parametrů vyhledávání provádí pomocí Base64-enkódovaného Protobufu v URL parametru tfs. Můžete buď reverzně analyzovat toto kódování, nebo zvolit jednodušší cestu: sestavit URL v přirozeném jazyce.

Nejjednodušší varianta používá formát vyhledávacího dotazu:

https://www.google.com/travel/flights?q=flights+from+SFO+to+JFK+on+2026-05-15&curr=USD

Pro větší kontrolu můžete URL generovat programově:

def build_flights_url(origin: str, destination: str, date: str) -> str:
    base = "https://www.google.com/travel/flights"
    query = f"flights from {origin} to {destination} on {date}"
    return f"{base}?q={query.replace(' ', '+')}&curr=USD"

Alternativa — reverzní inženýrství Protobuf kódování — dává přesnější kontrolu, ale přestává fungovat, jakmile Google změní interní formát. Knihovny jako fast-flights na GitHubu používají dekódování Protobufu, aby se vyhnuly parsování HTML úplně, ale jde o pokročilejší přístup.

Krok 3: Spuštění prohlížeče a otevření Google Flights

Tady je nastavení pro Playwright. Používáme playwright-stealth, abychom hned od začátku snížili riziko detekce.

import asyncio
from playwright.async_api import async_playwright
from playwright_stealth import Stealth

async def scrape_flights(params: SearchParams) -> List[FlightData]:
    async with Stealth().use_async(async_playwright()) as pw:
        browser = await pw.chromium.launch(
            headless=True,
            args=[
                "--disable-blink-features=AutomationControlled",
                "--disable-dev-shm-usage",
                "--no-first-run",
            ]
        )
        context = await browser.new_context(
            viewport={"width": 1920, "height": 1080},
            user_agent=(
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/125.0.0.0 Safari/537.36"
            ),
            locale="en-US",
            timezone_id="America/New_York",
        )
        # Přednastavíme cookie souhlasu, aby se přeskočilo okno s consentem
        await context.add_cookies([{
            "name": "SOCS",
            "value": "CAESHwgBEhJnd3NfMjAyNTAyMjctMF9SQzIaBXpoLUNOIAEaBgiAy6O-Bg",
            "domain": ".google.com",
            "path": "/"
        }])
        page = await context.new_page()

Pro produkční použití běžíme v headless režimu (pro ladění přepněte na headless=False), nastavujeme realistický viewport i user-agent a předem ukládáme cookie SOCS, aby se přeskočilo consent okno — o tom víc v části o anti-bot ochraně.

Krok 4: Přejděte na výsledky vyhledávání

Načtěte sestavenou URL a počkejte, až se objeví výsledky letů:

        url = build_flights_url(
            params.origin, params.destination, params.departure_date
        )
        await page.goto(url, wait_until="networkidle")

        # Počkáme na načtení výsledků letů
        await page.wait_for_selector(
            "li.pIav2d", timeout=15000
        )

Pokud zde dostáváte timeout, obvykle to znamená buď to, že stránku zablokovalo consent okno (viz oprava pomocí cookie ve 3. kroku), nebo Google servíruje CAPTCHA. Obojí řešíme v části o anti-bot ochraně.

Krok 5: Načtěte všechny výsledky letů

Google Flights skrývá další výsledky za tlačítkem „Show more flights“. Musíte na něj klikat opakovaně, dokud nejsou vidět všechny lety:

        # Klikáme na "Show more flights", dokud se nenačtou všechny výsledky
        while True:
            try:
                more_button = page.locator(
                    'button:has-text("Show more flights")'
                )
                if await more_button.is_visible(timeout=3000):
                    await more_button.click()
                    await page.wait_for_timeout(2000)
                else:
                    break
            except Exception:
                break

Tento cyklus tlačítko klikne, počká 2 sekundy na vykreslení nových výsledků a skončí, jakmile tlačítko zmizí. Podle mých testů má většina tras 1–3 stránky výsledků.

Krok 6: Extrahujte data o letu pomocí CSS selektorů

Teď z načtené stránky vyparsujeme samotná data o letu. Tady jsou selektory (ověřené k dubnu 2026 — viz sekce o údržbě níže, proč na tom datum záleží):

        flights = []
        cards = await page.query_selector_all("li.pIav2d")

        for card in cards:
            flight = FlightData()

            # Název aerolinky
            airline_el = await card.query_selector(
                "div.sSHqwe span:not([class])"
            )
            if airline_el:
                flight.airline = (await airline_el.inner_text()).strip()

            # Čas odletu
            dep_el = await card.query_selector(
                'span[aria-label*="Departure time"]'
            )
            if dep_el:
                flight.departure_time = (await dep_el.inner_text()).strip()

            # Čas příletu
            arr_el = await card.query_selector(
                'span[aria-label*="Arrival time"]'
            )
            if arr_el:
                flight.arrival_time = (await arr_el.inner_text()).strip()

            # Doba letu
            dur_el = await card.query_selector("div.gvkrdb")
            if dur_el:
                flight.duration = (await dur_el.inner_text()).strip()

            # Přestupy
            stops_el = await card.query_selector("div.EfT7Ae span")
            if stops_el:
                flight.stops = (await stops_el.inner_text()).strip()

            # Cena
            price_el = await card.query_selector(
                "div.FpEdX span"
            )
            if price_el:
                flight.price = (await price_el.inner_text()).strip()

            # Emise CO2
            co2_el = await card.query_selector("div.O7CXue")
            if co2_el:
                flight.co2_emissions = (
                    await co2_el.get_attribute("aria-label") or ""
                ).strip()

            flights.append(flight)

        await browser.close()
        return flights

Pozor: názvy tříd jako pIav2d, sSHqwe a FpEdX generuje Google Closure Compiler a mohou se změnit při libovolném buildu. Selektory přes aria-label jsou stabilnější. Níže ukážu strategii údržby.

Krok 7: Uložení výsledků do JSON nebo CSV

Nakonec si scrapovaná data uložte s časovým razítkem (to je klíčové pro pozdější sledování cen):

import json
from datetime import datetime
from dataclasses import asdict

async def main():
    params = SearchParams(
        origin="SFO",
        destination="JFK",
        departure_date="2026-05-15"
    )
    flights = await scrape_flights(params)

    output = {
        "search_date": datetime.now().isoformat(),
        "params": asdict(params),
        "flights": [asdict(f) for f in flights],
    }

    with open("flights.json", "w") as f:
        json.dump(output, f, indent=2)

    # Uložíme i CSV
    import pandas as pd
    df = pd.DataFrame([asdict(f) for f in flights])
    df["search_date"] = datetime.now().isoformat()
    df["route"] = f"{params.origin}-{params.destination}"
    df.to_csv("flights.csv", index=False)

    print(f"Scrapováno {len(flights)} letů")

asyncio.run(main())

Spusťte to a měli byste dostat flights.json i flights.csv s výsledky. V mých testech vrací vyhledání SFO-JFK obvykle 30–80 možností letu a dokončí se za zhruba 15–20 sekund.

Průvodce přežitím anti-bot ochrany při scrapování Google Flights

Většina návodů tady končí. Většina scraperů tady selže. Google v lednu 2025 nasadil SearchGuard, který přes noc rozbil téměř všechny SERP scrapery. Google to popisuje jako „výsledek desítek tisíc člověkohodin a milionů dolarů investic“. Google Flights je hodnocen jako 4/5 z hlediska obtížnosti scrapování.

Žádný konkurenční článek tohle nerozebírá do hloubky, a přitom je to hlavní důvod, proč scraperům lidem přestávají fungovat. Tady je, co proti vám stojí a jak na to.

anti-bot-survival-guide.webp

Náhodné prodlevy mezi požadavky

Nejjednodušší obrana proti rate limitu. Dva řádky kódu, střední účinnost:

import time
import random

time.sleep(random.uniform(3, 7))

Vložte to mezi přechody mezi stránkami. Pevné intervaly (například přesně 5 sekund pokaždé) jsou podezřelé — je potřeba je náhodně obměňovat.

Rotace User-Agentu

Posílat při každém požadavku stejný user-agent je snadno rozpoznatelný vzorec. Střídejte je ze seznamu:

import random

USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 Safari/605.1.15",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0",
]

user_agent = random.choice(USER_AGENTS)

Obejítí detekce headless režimu

Google kontroluje příznak navigator.webdriver i další automatizační signály. Knihovna playwright-stealth pokryje většinu z nich, ale měli byste zároveň použít i spouštěcí parametry z kroku 3. Klíčové přepínače:

args=[
    "--disable-blink-features=AutomationControlled",
    "--disable-dev-shm-usage",
    "--no-first-run",
]

To vás dostane přes základní detekci. SearchGuard jde hlouběji — sleduje rychlost pohybu myši, načasování kláves a vzory scrollování — ale pro scraping v nižším až středním objemu obvykle stačí stealth režim a realistické prodlevy.

Rotace proxy: datacentrové vs. rezidenční

Pro cokoliv nad pár vyhledání budete potřebovat proxy. Rozdíl je zásadní:

VlastnostDatacentrové proxyRezidenční proxy
Rychlost100–1 000 Mbps10–100 Mbps
Úspěšnost (Google)20–40 %85–95 %
Cena$0,10–$0,50/IP/měsíc$5–$15/GB
Riziko detekceVysokéVelmi nízké

Rezidenční proxy jsou při scrapování chráněných webů asi 180× levnější na úspěšný požadavek. Ceníky poskytovatelů v roce 2026: Smartproxy od $7/GB, Bright Data $8,40/GB, Oxylabs $8/GB.

Proxy přidáte do Playwrightu takto:

browser = await pw.chromium.launch(
    proxy={"server": "http://proxy-host:port",
           "username": "user", "password": "pass"}
)

Řešení vyskakovacího okna se souhlasem cookies

Uživatelé opakovaně uvádějí okno „Souhlasím s podmínkami“ jako blokující překážku: „nejdřív Google zobrazí vyskakovací okno 'souhlasím s podmínkami a pravidly'.“ Nejčistší řešení je přednastavit cookie SOCS (viz krok 3). Pokud to nestačí, klikněte přes něj:

try:
    accept_btn = page.locator('button:has-text("Accept all")')
    if await accept_btn.is_visible(timeout=3000):
        await accept_btn.click()
        await page.wait_for_timeout(1000)
except Exception:
    pass  # Žádné okno se nezobrazilo

Poznámka: text tlačítka se liší podle jazyka — v němčině „Alle akzeptieren“, ve francouzštině „Tout accepter“.

Rychlá přehledová tabulka anti-bot technik

TechnikaObtížnostÚčinnostJe potřeba kód?
Náhodné prodlevy (2–7 s)NízkáStřední2 řádky
Rotace user-agentuNízkáStřední5 řádků
Obejítí detekce headlessStředníVysokáLaunch args Playwrightu
Doplněk playwright-stealthStřední60–80 % u základních webůpip install
Rotace proxy (datacentrové)StředníStředníKonfigurace
Rotace proxy (rezidenční)Střední85–95 % úspěšnostKonfigurace
Přednastavení consent cookie (SOCS)NízkáNutné1 řádek

Doporučené bezpečné tempo: mezi požadavky držte prodlevy 10–20 sekund a rotujte IP adresy. Prahové hodnoty Googlu jsou zhruba 100 požadavků za minutu na jednu IP, než dostanete 429, a dlouhodobý objem nad 1 000 požadavků denně na IP může vyvolat dočasný ban.

Proč se vám stále rozbíjejí selektory pro Google Flights (a jak to opravit)

Tohle je zdaleka největší bolest. Fóra jsou plná variant typu „všechno, co mi vrací, jsou 14 prázdných seznamů.“ Každý návod vám dá selektory. Nikdo nevysvětlí, proč se rozbíjejí.

Proč se selektory Google Flights mění

Důvodů jsou tři:

  1. Obfuskace přes Closure Compiler. Google používá Closure Stylesheets k generování názvů tříd jako BVAVmf a YMlIz přes goog.setCssNameMapping(). Tyto názvy se mění s každým buildem — někdy i týdně.

  2. A/B testování. Různí uživatelé současně vidí různé HTML struktury. Váš scraper může fungovat u vás, ale selhat u někoho v jiném regionu.

  3. Rozdíly v lokalizaci. Uživatelé v EU vidí jiné termíny, rozložení i datová pole než uživatelé v USA.

Pište odolné selektory

Dávejte přednost selektorům založeným na významu, ne na vzhledu:

# Křehké — rozbije se při každém buildu
price_el = await card.query_selector("div.BVAVmf > div.YMlIz")

# Odolnější — navázané na accessibility label
sp_el = await card.query_selector('span[aria-label*="Departure time"]')

# Taky odolné — textová shoda
more_btn = page.locator('button:has-text("Show more flights")')

Hierarchie stability selektorů (od nejstabilnějšího po nejméně stabilní):

  1. aria-label atributy — souvisí s přístupností, mění se zřídka
  2. data-* atributy — přidávají se záměrně pro funkčnost
  3. role atributy — ARIA role jsou sémantické
  4. Selektory podle textu — shoda s viditelným obsahem
  5. Částečná shoda názvu třídy — např. [class*="price"]
  6. Plné obfuskované názvy tříd — pokud možno se jim vyhněte

Přidejte validační funkci

Nedovolte, aby rozbité selektory tiše vytvářely prázdná data. Zachyťte to hned:

import logging

logger = logging.getLogger(__name__)

def validate_flight(data: FlightData) -> bool:
    required = ["airline", "price", "departure_time",
                "arrival_time", "duration"]
    valid = True
    for field_name in required:
        if not getattr(data, field_name, ""):
            logger.warning(
                f"Chybí '{field_name}' — selektory bude možná potřeba aktualizovat"
            )
            valid = False
    return valid

Spouštějte ji na každý scrapovaný let. Jakmile se začnou objevovat varování, je čas stránku zkontrolovat a selektory upravit.

Strategie údržby selektorů

  • Kontrolujte selektory měsíčně, nebo ihned, jakmile klesne kvalita výstupu
  • Uchovávejte selektory v samostatném konfiguračním slovníku, aby šly snadno upravit
  • Selektory v tomto článku byly naposledy ověřeny: duben 2026
  • Zvažte knihovnu fast-flights jako alternativu — používá dekódování Protobufu místo CSS selektorů, takže tenhle problém obchází úplně (i když má vlastní zranitelnost, pokud Google změní interní datový formát)

Od jednorázového scrapu k automatickému sledování cen Google Flights

Většina návodů končí u „uložte do JSON“. Název tohoto článku ale slibuje „Price Alerts“. Tak pojďme doručit i to.

scraper-to-price-tracker-sfo-jfk.webp

Naplánujte automatické spuštění scraperu

Možnost 1: knihovna schedule v Pythonu (nejjednodušší, multiplatformní):

import schedule
import time

def run_scraper():
    asyncio.run(main())

schedule.every().day.at("06:00").do(run_scraper)
schedule.every().day.at("18:00").do(run_scraper)

while True:
    schedule.run_pending()
    time.sleep(60)

Možnost 2: cron úloha (Linux/Mac):

# Spustit každý den v 6:00 a 18:00
0 6,18 * * * cd /path/to/scraper && python scraper.py

Možnost 3: Windows Task Scheduler — vytvořte základní úlohu, která spouští python scraper.py podle zvoleného rozvrhu.

Nevýhoda: všechna tato řešení vyžadují stroj, který běží neustále. Pokud to poběží na notebooku, který uspáváte, o scrape přijdete.

Ukládání historických cenových dat

Místo přepisování JSON souboru je lepší data připojovat do SQLite databáze:

import sqlite3
from datetime import datetime

def init_db():
    conn = sqlite3.connect("flights.db")
    conn.execute("""
        CREATE TABLE IF NOT EXISTS flights (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            scrape_date TEXT NOT NULL,
            route TEXT NOT NULL,
            airline TEXT,
            departure_time TEXT,
            arrival_time TEXT,
            duration TEXT,
            stops TEXT,
            price_usd REAL,
            co2_emissions TEXT
        )
    """)
    conn.execute(
        "CREATE INDEX IF NOT EXISTS idx_route_date "
        "ON flights(route, scrape_date)"
    )
    conn.commit()
    return conn

def save_flight(conn, route: str, flight: FlightData):
    price_num = float(
        flight.price.replace("$", "").replace(",", "")
    ) if flight.price else None
    conn.execute(
        "INSERT INTO flights "
        "(scrape_date, route, airline, departure_time, "
        "arrival_time, duration, stops, price_usd, co2_emissions) "
        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
        (datetime.now().isoformat(), route, flight.airline,
         flight.departure_time, flight.arrival_time,
         flight.duration, flight.stops, price_num,
         flight.co2_emissions)
    )
    conn.commit()

Po týdnu scrapování dvakrát denně budete mít dost dat na první trendovou analýzu.

Analýza cenových trendů a nastavení upozornění

Najděte nejlevnější variantu v historických datech:

import pandas as pd
import sqlite3

conn = sqlite3.connect("flights.db")
df = pd.read_sql_query(
    "SELECT * FROM flights WHERE route = 'SFO-JFK'", conn
)
summary = df.groupby("scrape_date")["price_usd"].agg(
    ["min", "max", "mean"]
)
cheapest = df.loc[df["price_usd"].idxmin()]
print(
    f"Nejlevnější: ${cheapest['price_usd']:.0f} dne "
    f"{cheapest['scrape_date']} ({cheapest['airline']})"
)

Pošlete e-mailové upozornění, když cena klesne pod váš limit:

import smtplib
from email.mime.text import MIMEText

def send_price_alert(route, price, threshold, recipient):
    msg = MIMEText(
        f"Upozornění na pokles ceny! {route}: ${price:.0f} "
        f"(pod vaším limitem ${threshold:.0f})"
    )
    msg["Subject"] = f"Výhodná letenka: {route} za ${price:.0f}"
    msg["From"] = "alerts@example.com"
    msg["To"] = recipient

    with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
        server.login("alerts@example.com", "your_app_password")
        server.send_message(msg)

# Po každém scrapu zkontrolujte výhodné nabídky
min_price = df["price_usd"].min()
threshold = 250
if min_price < threshold:
    send_price_alert("SFO-JFK", min_price, threshold,
                     "you@email.com")

Doporučená frekvence scrapování: pro osobní sledování cen stačí dvakrát denně (náhodné časy snižují riziko detekce). Pro business monitoring každé 4–6 hodin. Hodinové scrapování jen během krátkodobých slev, a to pouze dočasně.

Snazší cesta: Thunderbit Scheduled Scraper

Pokud se vám konfigurace cron úloh, běžící server a proxy zdají jako příliš velká infrastruktura, Thunderbit's Scheduled Scraper zvládne stejný use case bez všech těchto starostí. Stačí popsat interval scrapování přirozeným jazykem, vložit URL vašich výsledků Google Flights a scraper běží automaticky na cloudové infrastruktuře Thunderbitu — s vestavěným řešením anti-bot ochrany a přímým exportem do Google Sheets, Excelu nebo Airtable. Není to náhrada za plně vlastní Python řešení (ztrácíte možnost hluboké customizace), ale pro konkrétní případ „chci tabulku se sledováním cen“ jde o nejrychlejší cestu. Vyzkoušet to můžete na bezplatném tarifu.

Když je Python zbytečně moc: no-code způsoby, jak scrapovat Google Flights

Po vybudování všeho výše řečeného musím být upřímný: je to spousta pohyblivých částí. Ne každý potřebuje takovou úroveň kontroly. Selektory se rozbíjejí, proxy se musí rotovat, cron úlohy je potřeba hlídat. Pokud je váš cíl „pravidelně dostávat ceny letenek do tabulky“, existují rychlejší možnosti.

Srovnání: vlastní Python vs. API služby vs. Thunderbit

PřístupČas na nastaveníNutnost kódováníŘeší anti-botPlánováníCena
DIY Playwright (tento návod)1–2 hodinyPython (středně pokročilý)Ruční konfiguraceRučně (cron)Zdarma + náklady na proxy
SerpApi Google Flights endpoint15 minJen API voláníZajištěnoPřes APIcca $50+/měsíc
Thunderbit Chrome Extension2 minŽádnéCloud scrapingVestavěný plánovačK dispozici zdarma

Poznámka k SerpApi: Google v prosinci 2025 podal žalobu podle DMCA na SerpApi, protože jejich požadavky měly během dvou let narůst o 25 000 %. Pokud zvažujete API poskytovatele, tahle právní nejistota stojí za zvážení.

Jak Thunderbit scrapuje Google Flights

Otevřete výsledky vyhledávání Google Flights v Chromu, klikněte v Thunderbitu na tlačítko „AI Suggest Fields“ — AI si přečte stránku a navrhne sloupce jako aerolinka, cena, čas odletu, přestupy — zkontrolujte navržená pole a klikněte na „Scrape“. Výsledky se objeví v tabulce, kterou lze exportovat do Excelu, Google Sheets, Airtable nebo Notion — vše na bezplatném tarifu.

Pro use case sledování cen konkrétně Thunderbit Scheduled Scraper a Cloud Scraping (který zvládne 50 stránek paralelně) nahradí celou infrastrukturu cron + proxy + server.

Python vám dá plnou kontrolu a neomezené možnosti přizpůsobení. Thunderbit přinese rychlost a nulovou údržbu. Záleží na vašem skutečném cíli. Pokud se chcete dozvědět víc o no-code přístupech, podívejte se na náš průvodce nejlepšími no-code web scrapery.

flight-data-options-comparison.webp

Je scrapování Google Flights legální? Co byste měli vědět

Uživatelé na fórech to řeší často: „přímé scrapování Google Flights porušuje podmínky používání Googlu.“ Je to oprávněná obava — zvlášť když bylo API zrušeno a neexistuje žádná oficiálně schválená alternativa.

Porušení podmínek vs. právní odpovědnost

Podmínky služby Googlu (aktualizované 22. května 2024) uvádějí, že uživatelé nesmějí „přistupovat ke službám nebo obsahu ani je používat prostřednictvím automatizovaných prostředků (například robotů, crawlerů nebo scraperů).“ Porušení ToS je porušení smlouvy (občanskoprávní věc) — není to totéž co porušení zákona.

Klíčový právní precedent: hiQ v. LinkedIn (9. obvod, 2022) stanovil, že scrapování veřejně dostupných dat neporušuje zákon CFAA (Computer Fraud and Abuse Act). Případ ale skončil smírem a prosincová žaloba Googlu na SerpApi v roce 2025 používá jinou právní teorii — DMCA § 1201 (obcházení technologických ochranných opatření) — která může být závažnější.

Nejlepší postupy pro odpovědné scrapování

  • Omezujte rychlost požadavků — prodlevy 10–20 sekund s rotací IP
  • Nescrapujte osobní údaje — ceny letenek jsou veřejně zobrazená agregovaná data
  • Neobcházejte CAPTCHA programově (to je právně citlivá oblast DMCA)
  • Používejte data pro osobní výzkum, ne pro vytváření konkurenčního komerčního produktu bez řádné licence
  • Zvažte oficiální API, pokud jsou k dispozici

Alternativní zdroje dat

Pokud vám scrapování pro váš use case přijde příliš riskantní, existují legitimní API možnosti:

PoskytovatelCenaFree tierPoznámky
SerpApi$75–$3 750+/měsíc250 vyhledávání/měsícPřímé Google Flights JSON (pod právním dohledem)
Kiwi TequilaZdarma (affiliate model)NeomezeněNejlepší pro startupy a testování
AmadeusPay-as-you-go2 000 pož./měsíc400+ aerolinek, možnost rezervace
SkyscannerIndividuálníVyžaduje schválení52 trhů, 30 jazyků

Podrobnější rozbor právních dopadů web scrapingu najdete v našem dalším článku.

Závěr a klíčová zjištění

Bylo toho hodně. Tohle je to podstatné:

  • Python + Playwright je nejflexibilnější cesta pro scraping Google Flights, ale vyžaduje průběžnou údržbu
  • Anti-bot opatření (prodlevy, rotace user-agentu, rezidenční proxy) nejsou volitelná — jsou nezbytná pro spolehlivost, zejména po SearchGuardu
  • Selektory se často rozbíjejí — používejte pokud možno aria-label a textové selektory, validujte výstup a mějte plán údržby
  • Automatizujte pomocí schedule nebo cronu, aby se jednorázový scrape změnil v reálný tracker cen s historickými daty a e-mailovými upozorněními
  • Thunderbit nabízí no-code alternativu s vestavěným plánováním, cloud scrapingem a anti-bot řešením — ideální, pokud chcete spíš tabulku se sledováním cen než programátorský projekt
  • Respektujte právní hranice — omezujte rychlost, scrapujte jen veřejná data a pro komerční použití zvažte API alternativy

Vezměte si kód z tohoto návodu, nebo si nainstalujte Thunderbit Chrome extension a jděte rychlejší cestou. V obou případech budete sledovat ceny letenek místo neustálého ručního obnovování Google Flights.

Další techniky Python scrapingu najdete v našich průvodcích jak scrapovat web v Pythonu a nejlepších Python nástrojích pro web scraping.

Často kladené dotazy

1. Můžu scrapovat Google Flights bez Pythonu?

Ano. API služby jako SerpApi a Kiwi Tequila poskytují strukturovaná letová data přes API volání (bez nutnosti automatizace prohlížeče). Pro plně no-code přístup umí Thunderbit Chrome extension scrapovat výsledky Google Flights přímo z vašeho prohlížeče s AI navrhovanými poli a exportem jedním kliknutím.

2. Blokuje Google scrapování letů?

Google používá detekci botů (SearchGuard), CAPTCHA a omezení rychlosti. S vhodnými anti-bot opatřeními — náhodné prodlevy, rotace user-agentu, rezidenční proxy a stealth nastavení prohlížeče — můžete při středním objemu udržet spolehlivé scrapování. Konkrétní techniky a prahy najdete v sekci o anti-bot ochraně výše.

3. Jak často bych měl scrapovat Google Flights pro sledování cen?

Dvakrát denně (v náhodných časech) stačí pro osobní sledování cen a zároveň drží riziko detekce nízko. Pro firemní monitoring každé 4–6 hodin s rotací proxy. Hodinové scrapování se vyplatí jen při krátkodobých slevách letenek — výrazně totiž zvyšuje šanci na blokaci.

4. Existuje zdarma Google Flights API?

Oficiální Google QPX Express API bylo ukončeno v dubnu 2018. Neexistuje žádná bezplatná oficiální náhrada. Nejbližší bezplatná možnost je Kiwi Tequila API (affiliate model, neomezené vyhledávání). SerpApi nabízí 250 bezplatných vyhledávání měsíčně. Pro většinu uživatelů je nejpraktičtější cesta scraping nebo no-code nástroj jako Thunderbit.

5. Proč mi CSS selektory pro Google Flights pořád vracejí prázdná data?

Google používá Closure Compiler k generování obfuskovaných názvů tříd, které se mění s každým buildem. HTML strukturu navíc mění i A/B testování a rozdíly v lokalizaci. Řešení: používejte aria-label atributy a textové selektory místo názvů tříd, přidejte validační funkci pro včasné zachycení rozbití a kontrolujte selektory každý měsíc. Podrobnosti najdete v části o údržbě selektorů.

Zjistěte více

Ke
Ke
CTO ve Thunderbit | Senior Data Scientist a expert na ML S téměř desetiletou zkušeností v oblasti strojového učení a datové vědy je Ke Shen absolventem Kolumbijské univerzity a bývalým Senior Data Scientist ve Walmart Labs. Díky hlubokým odborným znalostem v Pythonu, R, Javě a statistice, uznávaným i mezi kolegy, sdílí ověřené poznatky o tom, jak převést složité AI algoritmy od teorie až k produkční architektuře.
Obsah
Thunderbit · AI agent pro webová data

Extrahuj data z libovolné stránky za 1 kliknutí

Důvěřuje mu více než 250 000 uživatelů
k dispozici bezplatný plán
Z webové stránky do tabulky
Popiš, co potřebuješ — AI agent Thunderbit to nasbírá a exportuje do Excelu, Google Sheets, Airtable nebo Notion. Začni zdarma.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week