Google Flights’i Python ile Kazıyın: Koddan Fiyat Uyarılarına

Son güncelleme: August 20, 2026
Google Flights’i Python ile Kazıyın: Koddan Fiyat Uyarılarına

Google, Flights API’sini 2018’de kapattı; ama uçak bileti fiyatları durmaksızın değişmeye devam ediyor — tek bir yurt içi rotada 48 saat içinde 17 kez bile oynayabiliyor. Bu verilere programatik biçimde ulaşmak istiyorsanız, pratikte elinizde kalan tek yol kazıma yöntemi.

Google’dan uçuş verisi çekmek için uzun süre farklı yöntemleri denedim ve özellikle Google’ın Ocak 2025’te SearchGuard’ı devreye almasıyla iş iyice değişti. Bu rehberde, Playwright kullanarak Google Flights için çalışan bir Python kazıyıcıyı nasıl kuracağınızı, çoğu kişinin takıldığı anti-bot önlemlerini nasıl aşabileceğinizi ve ardından bu yapıyı otomatik fiyat takibi ve uyarı sistemine nasıl çevireceğinizi adım adım anlatacağım. Kodu tamamen uğraşmadan geçmek isterseniz, yaklaşık iki dakikada aynı sonuca ulaştıran kodsuz bir alternatif olarak Thunderbit seçeneğini de ekleyeceğim.

Neden Google Flights’i Python ile Kazımalısınız?

Google Flights, uçuş aramalarında baskın platform konumunda. ABD’de mobil görünürlüğü yüzde 47,6’ya yükseldi ve tüm büyük OTA’ları geride bıraktı. Arkadaki seyahat metaarama pazarı 2024’te 8,33 milyar dolar değerindeydi ve %30,2 CAGR ile büyüyor. Buna rağmen, QPX Express API’si 10 Nisan 2018’de kalıcı olarak kapandığından, bu verilere programatik erişim için resmi bir yol yok.

Öte yandan aynı güzergâhta uçak bileti fiyatları yüzde 50’ye kadar dalgalanabiliyor; en düşük ve en yüksek fiyat arasında ortalama yaklaşık 20 dolarlık fark görülüyor. Delta gibi havayolları dinamik fiyatlandırmada 77 ücret segmenti kullanıyor. 2026’nın başlarında ABD gidiş-dönüş ortalaması 408 dolar seviyesinde ve uçak biletleri yıllık bazda yüzde 14,9 daha yüksek.

Güçlü platform, API yok, fiyatlar oynak. Bu yüzden Google Flights’i Python ile kazımak, GitHub’da ve seyahat forumlarında en çok tercih edilen projelerden biri hâline geldi.

Kimler nasıl faydalanır, bir bakalım:

Kullanıcı TürüKullanım SenaryosuTemel Fayda
Bireysel yolcularBelirli rotaların fiyatlarını zaman içinde izlemekUçuş başına ortalama $50 tasarruf
Seyahat acenteleriRekabetçi fiyatlandırma istihbaratıGerçek zamanlı ücret paritesi takibi
Kurumsal seyahat ekipleriRotalar genelinde maliyet optimizasyonuKurumsal seyahatte %10–30 tasarruf
GeliştiricilerFiyat karşılaştırma uygulamaları geliştirmekFiyat verilerine programatik erişim
AraştırmacılarHavayolu fiyat oynaklığı analiziAkademik ve pazar araştırmaları

Forum kullanıcıları kazımaya neden yöneldiklerini açıkça söylüyor: “Google Flights API kapatıldı, bu yüzden web scraping kullanmam gerekiyor” düşüncesi sıkça karşınıza çıkıyor. Üstelik geri dönüş de güçlü — Hopper, günlük 5 milyardan fazla fiyat teklifini analiz ederek %95 tahmin doğruluğu sağladığını söylüyor; Expedia’nın 2026 verilerine göre ise 8–15 gün önceden rezervasyon yapmak iç hatlarda yaklaşık 25 dolar tasarruf sağlıyor.

Google Flights’ten Hangi Verileri Kazıyabilirsiniz?

Google Flights sonuç sayfası şaşırtıcı derecede zengin bir veri seti sunuyor. Genelde şu alanlar alınabiliyor:

  • Havayolu adı (ve logosu)
  • Kalkış saati ve havaalanı kodu
  • Varış saati ve havaalanı kodu
  • Toplam uçuş süresi
  • Aktarma sayısı ve aktarma detayları (havaalanı, süre, geceleme durumu)
  • Bilet fiyatı (para birimine göre)
  • CO2 emisyonu (kg CO2e, tipik uçuşlara göre yüzde farkla birlikte)
  • Seyahat sınıfı, uçuş numarası, uçak modeli
  • Diz mesafesi bilgileri
  • Ek özellikler (Wi‑Fi, priz, medya akışı)
  • Fiyat seviyesi göstergesi (düşük/ortalama/yüksek)
  • Gecikme uyarıları ("Sık sık 30 dakikadan fazla gecikir")

Veri erişimi rotaya, tarihe ve bilet tipine (tek yön / gidiş-dönüş) göre değişebilir. Tek bir kazınmış uçuş kaydı JSON olarak kabaca şöyle görünür:

{
  "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"
    }
  ]
}

Python Ortamınızı Kurma

Herhangi bir kazıma kodu yazmadan önce bazı hazırlıklar yapmanız gerekiyor.

Ön Koşullar:

  • Zorluk: Orta seviye
  • Gereken Süre: Tüm eğitim için yaklaşık 1–2 saat
  • Gerekenler: Python 3.7+, temel Python bilgisi, Chrome tabanlı bir tarayıcı

Gerekli Kütüphaneleri Yükleyin

Tarayıcı otomasyonu için Playwright kullanıyoruz (Google Flights tamamen JavaScript ile render edilir — statik HTTP istekleri işe yarar veri döndürmez), ayrıca birkaç yardımcı araç ekliyoruz:

pip install playwright playwright-stealth pandas
playwright install chromium
  • Playwright — headless tarayıcı otomasyonu, JavaScript render etme, yerleşik bekleme mekanizmaları
  • playwright-stealth — yaygın bot algılama sinyallerini yamalar
  • pandas — ileride veri analizi ve CSV dışa aktarma için

Neden Selenium veya Requests Yerine Playwright?

Google Flights, yalnızca requests + BeautifulSoup ile çalışmaz — sayfa içeriği tamamen JavaScript tarafından oluşturulur. Gerçek bir tarayıcıya ihtiyacınız var.

ÖzellikPlaywrightSeleniumrequests + BS4
JS render desteğiTam destekTam destekYok
HızToplamda %42 daha hızlıReferans seviyeBu kullanım için geçersiz
Async desteğiYerleşikSadece sıralıGeçersiz
Bellek kullanımıYüzde 30 daha azDaha yüksekMinimum
Bot algılamayı aşmaİyi (stealth ile)Daha kolay tespit edilirGeçersiz

Playwright daha hızlı, daha modern ve async desteği daha güçlüdür. Google Flights özelinde net kazanan odur.

Adım Adım: Google Flights’i Python ile Nasıl Kazırsınız?

Bu, rehberin ana kısmı. Kazıyıcıyı adım adım kuracağız.

google-flights-scraping-workflow.webp

1. Adım: Veri Sınıflarını Tanımlayın

İlk olarak arama parametrelerinizi ve uçuş verilerinizi Python dataclass’lerle yapılandırın. Bu, kodunuzu düzenli tutar ve ileride genişletmeyi kolaylaştırır.

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

@dataclass
class SearchParams:
    origin: str          # örn. "SFO"
    destination: str     # örn. "JFK"
    departure_date: str   # örn. "2026-05-15"
    return_date: Optional[str] = None
    trip_type: str = "one-way"  # "one-way" ya da "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 = ""

Her alan, sayfadan çekeceğimiz veriye doğrudan karşılık gelir. Bu yapıyı en başta kurmanız, sonradan ortalıkta dağınık sözlüklerle dolaşmamanızı sağlar.

2. Adım: Google Flights URL Yapısını Anlayın

Google Flights, arama parametrelerini tfs URL parametresi içinde Base64 ile kodlanmış Protobuf biçiminde taşır. İsterseniz bu kodlamayı tersine mühendislik yapabilirsiniz; ama daha kolay bir yol da var: doğal dil benzeri bir sorgu URL’si oluşturmak.

En basit yöntem şu arama biçimidir:

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

Daha fazla kontrol için URL’yi programatik olarak da oluşturabilirsiniz:

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"

Diğer seçenek — Protobuf kodlamasını tersine mühendislik yapmak — daha hassas kontrol sağlar; ancak Google iç formatı değiştirdiğinde kolayca bozulur. GitHub’daki fast-flights gibi kütüphaneler HTML ayrıştırmaya hiç girmeden Protobuf çözümlemesi kullanır; fakat bu daha ileri seviye bir yaklaşımdır.

3. Adım: Tarayıcıyı Başlatın ve Google Flights’e Gidin

İşte Playwright kurulumu. Başlangıçtan itibaren tespit riskini azaltmak için playwright-stealth kullanıyoruz.

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",
        )
        # Çerez onayını önceden ayarlayıp açılır pencereyi atla
        await context.add_cookies([{
            "name": "SOCS",
            "value": "CAESHwgBEhJnd3NfMjAyNTAyMjctMF9SQzIaBXpoLUNOIAEaBgiAy6O-Bg",
            "domain": ".google.com",
            "path": "/"
        }])
        page = await context.new_page()

Üretimde headless çalışıyoruz (hata ayıklarken headless=False yapın), gerçekçi bir viewport ve user-agent ayarlıyoruz ve SOCS çerezini önceden ekleyerek onay penceresini atlıyoruz — anti-bot bölümünde buna daha detaylı döneceğim.

4. Adım: Arama Sonuçlarına Gitme

Oluşturduğunuz URL’yi açın ve uçuş sonuçlarının yüklenmesini bekleyin:

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

        # Uçuş sonuçlarının yüklenmesini bekle
        await page.wait_for_selector(
            "li.pIav2d", timeout=15000
        )

Burada zaman aşımı görürseniz, genellikle ya onay penceresi sayfayı engellemiştir (3. adımda çerez çözümü) ya da Google CAPTCHA sunuyordur. İkisini de anti-bot bölümünde ele alacağız.

5. Adım: Tüm Uçuş Sonuçlarını Yükleyin

Google Flights, ek sonuçları "Show more flights" düğmesinin arkasına saklar. Tüm uçuşlar görünene kadar bu düğmeye tekrar tekrar tıklamanız gerekir:

        # Tüm sonuçlar yüklenene kadar "Show more flights" düğmesine tıkla
        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

Bu döngü düğmeye tıklar, yeni sonuçların render edilmesi için 2 saniye bekler ve düğme artık görünmüyorsa durur. Testlerimde çoğu rota 1–3 sayfalık sonuç veriyor.

6. Adım: CSS Seçicilerle Uçuş Verisini Çekin

Şimdi yüklenen sayfadan gerçek uçuş verisini ayrıştıralım. İşte seçiciler (Nisan 2026 itibarıyla doğrulandı — bu tarihin neden önemli olduğunu bakım bölümünde anlatacağım):

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

        for card in cards:
            flight = FlightData()

            # Havayolu adı
            airline_el = await card.query_selector(
                "div.sSHqwe span:not([class])"
            )
            if airline_el:
                flight.airline = (await airline_el.inner_text()).strip()

            # Kalkış saati
            dep_el = await card.query_selector(
                'span[aria-label*="Departure time"]'
            )
            if dep_el:
                flight.departure_time = (await dep_el.inner_text()).strip()

            # Varış saati
            arr_el = await card.query_selector(
                'span[aria-label*="Arrival time"]'
            )
            if arr_el:
                flight.arrival_time = (await arr_el.inner_text()).strip()

            # Süre
            dur_el = await card.query_selector("div.gvkrdb")
            if dur_el:
                flight.duration = (await dur_el.inner_text()).strip()

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

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

            # CO2 emisyonu
            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

Dikkat: pIav2d, sSHqwe ve FpEdX gibi class adları Google’ın Closure Compiler’ı tarafından üretildiği için her sürümde değişebilir. aria-label tabanlı seçiciler daha stabildir. Aşağıda kapsamlı bir bakım stratejisi de anlatıyorum.

7. Adım: Sonuçları JSON veya CSV Olarak Kaydedin

Son olarak, kazınan verileri zaman damgasıyla kaydedin (sonradan fiyat takibi için kritik):

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)

    # CSV olarak da kaydet
    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"{len(flights)} uçuş kazındı")

asyncio.run(main())

Bunu çalıştırdığınızda sonuçlarla birlikte bir flights.json ve flights.csv dosyası oluşmalı. Testlerimde SFO-JFK araması genellikle 30–80 uçuş seçeneği döndürüyor ve yaklaşık 15–20 saniyede tamamlanıyor.

Google Flights Kazımada Anti-Bot Hayatta Kalma Rehberi

Çoğu rehber burada biter. Çoğu kazıyıcı da burada başarısız olur. Google, Ocak 2025’te SearchGuard’ı devreye aldı ve bu, neredeyse tüm SERP kazıyıcılarını bir gecede bozdu. Google bunu, "on binlerce insan-saat ve milyonlarca dolarlık yatırımın ürünü" olarak tanımlıyor. Google Flights, kazıma zorluğu açısından 5 üzerinden 4 olarak değerlendiriliyor.

Rakip yazıların hiçbiri bunu derinlemesine anlatmıyor; oysa insanların kazıyıcılarının çalışmayı bırakmasının bir numaralı nedeni bu. Karşı karşıya olduğunuz şey ve nasıl başa çıkacağınız burada.

anti-bot-survival-guide.webp

İstekler Arasında Rastgele Gecikmeler

Hız sınırlamasına karşı en basit savunma. İki satır kod, orta düzey etki:

import time
import random

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

Bunu sayfa geçişleri arasına ekleyin. Sabit aralıklar (örneğin her zaman tam 5 saniye) şüphe uyandırır — aralığı rastgeleleştirin.

User-Agent Döndürme

Her istekte aynı user-agent dizesini göndermek kolayca fark edilir. Bir liste üzerinden döndürün:

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)

Headless Algılamayı Aşma

Google, navigator.webdriver bayrağını ve diğer otomasyon sinyallerini kontrol eder. playwright-stealth kütüphanesi bunların çoğunu ele alır; ancak 3. adımda gösterilen başlatma argümanlarını da kullanmalısınız. Önemli bayraklar:

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

Bu, temel algılamayı aşmanızı sağlar. SearchGuard daha derine iner — fare hızı, klavye zamanlaması ve kaydırma desenlerini izler — ama orta hacimli kazımada stealth modu ve gerçekçi gecikmeler genelde yeterlidir.

Proxy Döndürme: Veri Merkezi mi, Residential mı?

Birkaç aramanın ötesine geçiyorsanız proxy gerekir. Aradaki fark önemli:

ÖzellikVeri Merkezi Proxy’leriResidential Proxy’ler
Hız100–1.000 Mbps10–100 Mbps
Başarı oranı (Google)Yüzde 20–40Yüzde 85–95
MaliyetIP başına ayda $0.10–$0.50GB başına $5–$15
Tespit riskiYüksekÇok düşük

Korunan siteleri kazırken residential proxy’ler, başarılı istek başına yaklaşık 180 kat daha ucuzdur. 2026’daki sağlayıcı fiyatları: Smartproxy GB başına $7’dan, Bright Data $8,40/GB, Oxylabs $8/GB.

Playwright’a proxy eklemek için:

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

Çerez Onay Açılır Penceresini Yönetme

Kullanıcılar sık sık "şartları kabul et" penceresini bir engel olarak raporluyor: "önce google size 'şartlar ve koşulları kabul ediyorum' penceresini gösterir." En temiz çözüm, 3. adımda gösterildiği gibi SOCS çerezini önceden ayarlamak. Bu işe yaramazsa, pencereyi tıklayarak geçin:

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  # Açılır pencere yok

Not: Düğme metni yerel dile göre değişir — Almanca’da "Alle akzeptieren", Fransızca’da "Tout accepter".

Anti-Bot Hızlı Referans

TeknikZorlukEtkililikKod Gerekli mi?
Rastgele gecikmeler (2–7 sn)DüşükOrta2 satır
User-agent döndürmeDüşükOrta5 satır
Headless algılamayı aşmaOrtaYüksekPlaywright başlatma argümanları
playwright-stealth eklentisiOrtaTemel sitelerde %60–80pip install
Proxy döndürme (veri merkezi)OrtaOrtaYapılandırma
Proxy döndürme (residential)Orta%85–95 başarıYapılandırma
Çerez onayı ön ayarı (SOCS)DüşükGerekli1 satır

Önerilen güvenli hızlar için: IP döndürmeyle birlikte istekler arasında 10–20 saniye gecikme bırakın. Google’ın eşikleri yaklaşık olarak IP başına dakikada 100 istektir; IP başına günde 1.000’in üzerindeki sürekli kullanım geçici engelleri tetikleyebilir.

Google Flights Seçicileriniz Neden Sürekli Bozuluyor? (Ve Nasıl Düzeltilir)

En büyük sorun, açık ara bu. Forum başlıkları "geriye sadece 14 boş liste dönüyor" tarzı varyasyonlarla dolu. Her rehber size seçicileri veriyor; ama hiçbiri neden bozulduklarını açıklamıyor.

Google Flights Seçicileri Neden Değişir?

Bunun üç temel nedeni var:

  1. Closure Compiler ile karartma. Google, goog.setCssNameMapping() aracılığıyla BVAVmf ve YMlIz gibi class adları üretmek için Closure Stylesheets kullanır. Bunlar her derlemede — bazen haftalık olarak — değişir.

  2. A/B testleri. Farklı kullanıcılar aynı anda farklı HTML yapıları görebilir. Kazıyıcınız sizde çalışırken başka bir bölgede yaşayan kullanıcıda başarısız olabilir.

  3. Yerel dil farkları. AB kullanıcıları ABD kullanıcılarından farklı terimler, düzenler ve hatta veri alanları görür.

Dayanıklı Seçiciler Yazın

Görünüşten çok anlama dayalı seçicileri tercih edin:

# Kırılgan — her sürümde bozulabilir
price_el = await card.query_selector("div.BVAVmf > div.YMlIz")

# Daha dayanıklı — erişilebilirlik etiketlerine bağlı
 dep_el = await card.query_selector('span[aria-label*="Departure time"]')

# Yine dayanıklı — metin tabanlı eşleşme
more_btn = page.locator('button:has-text("Show more flights")')

Seçici dayanıklılığı sıralaması (en dayanıklından en zayıfa):

  1. aria-label öznitelikleri — erişilebilirliğe bağlıdır, nadiren değişir
  2. data-* öznitelikleri — işlev için açıkça eklenir
  3. role öznitelikleri — ARIA rolleri anlamsaldır
  4. Metin tabanlı seçiciler — görünen içeriği eşler
  5. Alt dize class eşleşmesi — örn. [class*="price"]
  6. Tam karartılmış class adları — mümkünse kaçının

Bir Doğrulama Fonksiyonu Ekleyin

Bozuk seçicilerin sessizce boş veri üretmesine izin vermeyin. Sorunu erken yakalayın:

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"Eksik '{field_name}' — seçicilerin güncellenmesi gerekebilir"
            )
            valid = False
    return valid

Bunu kazınan her uçuş üzerinde çalıştırın. Uyarılar görmeye başlarsanız, sayfayı inceleyip seçicilerinizi güncelleme zamanı gelmiş demektir.

Seçici Bakım Stratejisi

  • Seçicileri aylık olarak ya da çıktı kalitesi düştüğünde hemen kontrol edin
  • Kolay güncelleme için seçicileri ayrı bir yapılandırma sözlüğünde tutun
  • Bu makaledeki seçiciler en son Nisan 2026’da doğrulandı
  • Alternatif olarak fast-flights kütüphanesini değerlendirin — CSS seçiciler yerine Protobuf çözümlemesi kullanır ve bu sorunu tamamen by-pass eder (Google iç veri formatlarını değiştirdiğinde onun da kırılganlıkları vardır)

Tek Seferlik Kazıma İşinden Otomatik Google Flights Fiyat Takipçisine

Çoğu rehber "JSON’a kaydet" aşamasında biter. Bu yazının başlığında ise "Price Alerts" var. Şimdi bunu gerçeğe dönüştürelim.

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

Kazıyıcınızı Otomatik Çalışacak Şekilde Zamanlayın

Seçenek 1: Python schedule kütüphanesi (en basit, platformlar arası):

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)

Seçenek 2: cron işi (Linux/Mac):

# Her gün sabah 6 ve akşam 6'da çalıştır
0 6,18 * * * cd /path/to/scraper && python scraper.py

Seçenek 3: Windows Task Scheduler — tercih ettiğiniz programa göre python scraper.py çalıştıran basit bir görev oluşturun.

Bedeli şu: Bunların hepsi sürekli açık bir makine gerektirir. Bu işi uyku moduna geçen bir dizüstü bilgisayarda çalıştırıyorsanız, kazımaları kaçırırsınız.

Geçmiş Fiyat Verilerini Saklayın

Bir JSON dosyasını üzerine yazmak yerine veriyi SQLite veritabanına ekleyin:

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()

İki günde bir yapılan kazımalarla bir hafta sonunda, trendleri fark etmeye yetecek kadar veri biriktirmiş olursunuz.

Fiyat Trendlerini Analiz Edin ve Uyarılar Kurun

Geçmiş verinizdeki en ucuz seçeneği bulun:

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"En ucuz: ${cheapest['price_usd']:.0f} — "
    f"{cheapest['scrape_date']} ({cheapest['airline']})"
)

Fiyat belirlediğiniz eşik altına düştüğünde e-posta uyarısı tetikleyin:

import smtplib
from email.mime.text import MIMEText

def send_price_alert(route, price, threshold, recipient):
    msg = MIMEText(
        f"Fiyat düştü! {route}: ${price:.0f} "
        f"(belirlediğiniz ${threshold:.0f} eşiğinin altında)"
    )
    msg["Subject"] = f"Uçuş Fırsatı: {route} ${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)

# Her kazımadan sonra fırsat var mı kontrol et
min_price = df["price_usd"].min()
threshold = 250
if min_price < threshold:
    send_price_alert("SFO-JFK", min_price, threshold,
                     "you@email.com")

Önerilen kazıma sıklığı: kişisel fiyat takibi için günde iki kez yeterlidir (rastgele zamanlama tespit riskini azaltır). İş amaçlı izleme için her 4–6 saatte bir uygundur. Kısa süreli kampanya dönemleri dışında saatlik kazımadan kaçının; engellenme ihtimalini ciddi biçimde artırır.

Kolay Yol: Thunderbit’in Zamanlanmış Scraper’ı

Eğer cron işleri, sürekli açık bir sunucu ve proxy yapılandırmaları size gereğinden fazla altyapı gibi geliyorsa, Thunderbit’in Scheduled Scraper özelliği aynı kullanım senaryosunu bunların hiçbirine gerek olmadan çözer. Kazıma aralığını düz metin olarak tarif edersiniz, Google Flights URL’lerinizi girersiniz ve kazıyıcı Thunderbit’in bulut altyapısında otomatik çalışır — anti-bot yönetimi dahildir ve sonuçlar doğrudan Google Sheets, Excel veya Airtable içine aktarılabilir. Tam Python yaklaşımının yerini almaz (özelleştirme esnekliğini kaybedersiniz), ama hedefiniz spesifik olarak "fiyat takip tablosu oluşturmak" ise en hızlı yoldur. Bunu ücretsiz planda deneyebilirsiniz.

Python Fazla Ağırsa: Google Flights’i Kodsuz Kazıma Yolları

Yukarıdakilerin hepsini kurduktan sonra dürüst olayım: Bu sistem oldukça parçalı. Herkesin bu kadar kontrol ihtiyacı yok. Seçiciler bozulur, proxy’ler döner, cron işleri izlenmek zorunda kalır. Amacınız düzenli olarak "uçak bileti fiyatlarını bir tabloya almak" ise daha hızlı seçenekler var.

Karşılaştırma: Kendin Yap Python vs. API Servisleri vs. Thunderbit

YaklaşımKurulum SüresiKod GereksinimiAnti-Bot YönetimiZamanlamaMaliyet
Kendin yap Playwright (bu rehber)1–2 saatPython (orta seviye)Manuel yapılandırmaManuel (cron)Ücretsiz + proxy maliyeti
SerpApi Google Flights uç noktası15 dkYalnızca API çağrılarıYönetiliyorAPI üzerinden~$/ay 50+
Thunderbit Chrome Uzantısı2 dkYokBulut kazımaYerleşik zamanlayıcıÜcretsiz plan mevcut

SerpApi hakkında bir not: Google, Aralık 2025’te SerpApi’ye karşı bir DMCA davası açtı ve iki yıl içinde isteklerinin %25.000 arttığını iddia etti. API sağlayıcılarını değerlendirirken bu hukuki belirsizliği de göz önünde bulundurmak gerekir.

Thunderbit Google Flights’i Nasıl Kazır?

Google Flights arama sonuçlarınızı Chrome’da açın, Thunderbit’in "AI Suggest Fields" düğmesine tıklayın — yapay zeka sayfayı okuyup havayolu, fiyat, kalkış saati, aktarma sayısı gibi sütunlar önerir — önerilen alanları gözden geçirin ve "Scrape"e tıklayın. Sonuçlar Excel, Google Sheets, Airtable veya Notion’a aktarabileceğiniz bir tabloda görünür — hepsi ücretsiz planda.

Özellikle fiyat takibi senaryosunda, Thunderbit’in Scheduled Scraper ve Cloud Scraping özellikleri (aynı anda 50 sayfayı işleyebilir) cron + proxy + sunucu altyapısının tamamını ortadan kaldırır.

Python size tam kontrol ve sınırsız özelleştirme sunar. Thunderbit ise hız ve sıfır bakım sağlar. Seçiminizi gerçek hedefinize göre yapın. Kodsuz kazıma yaklaşımları hakkında daha fazla bilgi istiyorsanız, en iyi kodsuz web kazıyıcılar rehberimize göz atın.

flight-data-options-comparison.webp

Google Flights’i Kazımak Yasal mı? Bilmeniz Gerekenler

Forum kullanıcıları bunu sık sık gündeme getiriyor: "Google Flights’i doğrudan kazımak Google’ın TOS’unu ihlal eder." Özellikle API kapatıldığı ve onaylı bir alternatif olmadığı için bu anlaşılır bir endişe.

TOS İhlali ile Hukuki Sorumluluk Arasındaki Fark

Google’ın Hizmet Şartları (22 Mayıs 2024 güncellemesi), kullanıcıların "robotlar, örümcekler veya scraper’lar gibi otomatik yollarla hizmetlere veya içeriklere erişmemesi ya da kullanmaması" gerektiğini belirtir. TOS ihlali bir sözleşme ihlalidir (hukukî bir mesele) — yasa çiğnemekle aynı şey değildir.

Önemli hukuki emsal: hiQ v. LinkedIn (Ninth Circuit, 2022), herkese açık veriyi kazımanın Computer Fraud and Abuse Act’i (CFAA) ihlal etmediğini ortaya koydu. Ancak dava uzlaşmayla sonuçlandı ve Google’ın Aralık 2025’te SerpApi’ye açtığı dava farklı bir hukuki teori kullanıyor — DMCA Section 1201 (teknolojik koruma önlemlerini aşma) — bu da potansiyel olarak daha ciddi.

Sorumlu Kazıma İçin En İyi Uygulamalar

  • İsteklerinizi hız sınırına tabi tutun — IP döndürmeyle 10–20 saniyelik gecikmeler
  • Kişisel veri kazımayın — uçak bileti fiyatları herkese açık toplu verilerdir
  • CAPTCHA’ları programatik olarak aşmayın (burada DMCA riski var)
  • Veriyi kişisel araştırma için kullanın, uygun lisans olmadan rakip ticari ürün oluşturmak için değil
  • Mümkünse resmi API’leri değerlendirin

Alternatif Veri Kaynakları

Kullanım senaryonuz için kazıma fazla riskliyse, meşru API seçenekleri de var:

SağlayıcıMaliyetÜcretsiz PlanNotlar
SerpApiAyda $75–$3.750+Ayda 250 aramaDoğrudan Google Flights JSON’u (hukuki inceleme altında)
Kiwi TequilaÜcretsiz (affiliate modeli)SınırsızStartuplar ve testler için en iyi seçenek
AmadeusKullandıkça ödeAyda 2.000 istek400+ havayolu, rezervasyon yeteneği
SkyscannerÖzel fiyatlandırmaOnay gerekir52 pazar, 30 dil

Daha kapsamlı resmi tablo için web scraping’in hukuki sonuçları hakkındaki daha derin rehberimizi okuyabilirsiniz.

Sonuç ve Önemli Çıkarımlar

Epey yoğun bir içerikti. Önemli olanlar şunlar:

  • Python + Playwright, Google Flights kazımak için en esnek yaklaşımdır; ama düzenli bakım ister
  • Anti-bot önlemleri (gecikmeler, user-agent döndürme, residential proxy’ler) opsiyonel değil — özellikle SearchGuard sonrası güvenilirlik için şart
  • Seçiciler sık sık bozulur — mümkün olduğunda aria-label ve metin tabanlı seçiciler kullanın, çıktınızı doğrulayın ve bakım takvimi oluşturun
  • schedule veya cron ile otomasyon kurun; tek seferlik kazımayı geçmiş veriler ve e-posta uyarıları olan gerçek bir fiyat takipçisine dönüştürün
  • Thunderbit, yerleşik zamanlama, bulut kazıma ve anti-bot yönetimiyle kodsuz bir alternatif sunar — hedefiniz kod projesi değil de fiyat takip tablosuysa ideal
  • Yasal sınırları gözetin — hız sınırlaması uygulayın, yalnızca herkese açık verileri kazıyın ve ticari kullanım için API alternatiflerini düşünün

Bu rehberdeki kodu alın ya da hızlı yol için Thunderbit Chrome uzantısını yükleyin. Hangi yolu seçerseniz seçin, artık Google Flights’i elle yenilemek yerine uçuş fiyatlarını takip ediyor olacaksınız.

Daha fazla Python kazıma tekniği için Python ile web scraping nasıl yapılır ve en iyi Python web scraping araçları rehberlerimize göz atın.

SSS

1. Python olmadan Google Flights kazıyabilir miyim?

Evet. SerpApi ve Kiwi Tequila gibi API servisleri, yapılandırılmış uçuş verisini API çağrılarıyla sunar (tarayıcı otomasyonu gerekmez). Tamamen kodsuz bir yaklaşım için, Thunderbit’in Chrome uzantısı, AI önerili alanlarla ve tek tıkla dışa aktarma özelliğiyle Google Flights sonuçlarını doğrudan tarayıcınızdan kazıyabilir.

2. Google uçuş kazımayı engelliyor mu?

Google, bot algılama (SearchGuard), CAPTCHA ve hız sınırlaması kullanır. Doğru anti-bot önlemleriyle — rastgele gecikmeler, user-agent döndürme, residential proxy’ler ve stealth tarayıcı ayarları — orta hacimlerde güvenilir kazımayı sürdürebilirsiniz. Belirli teknikler ve eşikler için yukarıdaki anti-bot bölümüne bakın.

3. Fiyat takibi için Google Flights’i ne sıklıkla kazımalıyım?

Günde iki kez (rastgele saatlerde) kazıma, kişisel fiyat takibi için yeterlidir ve tespit riskini düşük tutar. İş amaçlı izleme için her 4–6 saatte bir, proxy döndürmeyle birlikte. Kısa süreli kampanyalar dışında saatlik kazımadan kaçının; engellenme ihtimalini belirgin biçimde artırır.

4. Ücretsiz bir Google Flights API var mı?

Resmi Google QPX Express API’si Nisan 2018’de kapatıldı. Yerini alan resmi bir ücretsiz çözüm yok. En yakın ücretsiz seçenek, Kiwi Tequila API (affiliate modeli, sınırsız arama). SerpApi ayda 250 ücretsiz arama sunuyor. Çoğu kullanıcı için kazıma veya Thunderbit gibi kodsuz bir araç pratik çözümdür.

5. Google Flights CSS seçicilerim neden sürekli boş veri döndürüyor?

Google, her derlemede değişen karartılmış class adları üretmek için Closure Compiler kullanır. A/B testleri ve yerel dil farkları da HTML yapısını kullanıcıdan kullanıcıya değiştirebilir. Çözüm: class adları yerine aria-label özniteliklerini ve metin tabanlı seçicileri kullanın, kırılmaları erken yakalamak için bir doğrulama fonksiyonu ekleyin ve seçicilerinizi aylık kontrol edin. Ayrıntılı strateji için seçici bakım bölümüne bakın.

Daha Fazla Bilgi

Ke
Ke
Thunderbit’ta CTO | Kıdemli Veri Bilimci ve ML Uzmanı Makine öğrenimi ve veri bilimi alanında yaklaşık on yıllık deneyime sahip olan Ke Shen, Columbia University mezunu ve Walmart Labs’te eski Kıdemli Veri Bilimci’dir. Python, R, Java ve İstatistik konularında derin ve meslektaşları tarafından tanınan uzmanlığıyla, karmaşık yapay zekâ algoritmalarını teoriden üretim düzeyinde mimariye taşıma konusunda sahada test edilmiş içgörüler paylaşır.
İçindekiler
Thunderbit · AI web veri ajanı

Herhangi bir sayfadan 1 tık içinde veri çıkar

250.000+ kullanıcı tarafından güveniliyor
ücretsiz plan mevcut
Web sayfasından tabloya
İhtiyacını anlat — Thunderbit’in AI Ajanı bunu çeker ve Excel, Google Sheets, Airtable veya Notion’a aktarır. Başlamak ücretsiz.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week