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 Senaryosu | Temel Fayda |
|---|---|---|
| Bireysel yolcular | Belirli rotaların fiyatlarını zaman içinde izlemek | Uçuş başına ortalama $50 tasarruf |
| Seyahat acenteleri | Rekabetçi fiyatlandırma istihbaratı | Gerçek zamanlı ücret paritesi takibi |
| Kurumsal seyahat ekipleri | Rotalar genelinde maliyet optimizasyonu | Kurumsal seyahatte %10–30 tasarruf |
| Geliştiriciler | Fiyat karşılaştırma uygulamaları geliştirmek | Fiyat verilerine programatik erişim |
| Araştırmacılar | Havayolu fiyat oynaklığı analizi | Akademik 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.
| Özellik | Playwright | Selenium | requests + BS4 |
|---|---|---|---|
| JS render desteği | Tam destek | Tam destek | Yok |
| Hız | Toplamda %42 daha hızlı | Referans seviye | Bu kullanım için geçersiz |
| Async desteği | Yerleşik | Sadece sıralı | Geçersiz |
| Bellek kullanımı | Yüzde 30 daha az | Daha yüksek | Minimum |
| Bot algılamayı aşma | İyi (stealth ile) | Daha kolay tespit edilir | Geç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.

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.

İ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:
| Özellik | Veri Merkezi Proxy’leri | Residential Proxy’ler |
|---|---|---|
| Hız | 100–1.000 Mbps | 10–100 Mbps |
| Başarı oranı (Google) | Yüzde 20–40 | Yüzde 85–95 |
| Maliyet | IP başına ayda $0.10–$0.50 | GB başına $5–$15 |
| Tespit riski | Yü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
| Teknik | Zorluk | Etkililik | Kod Gerekli mi? |
|---|---|---|---|
| Rastgele gecikmeler (2–7 sn) | Düşük | Orta | 2 satır |
| User-agent döndürme | Düşük | Orta | 5 satır |
| Headless algılamayı aşma | Orta | Yüksek | Playwright başlatma argümanları |
| playwright-stealth eklentisi | Orta | Temel sitelerde %60–80 | pip install |
| Proxy döndürme (veri merkezi) | Orta | Orta | Yapılandırma |
| Proxy döndürme (residential) | Orta | %85–95 başarı | Yapılandırma |
| Çerez onayı ön ayarı (SOCS) | Düşük | Gerekli | 1 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:
-
Closure Compiler ile karartma. Google,
goog.setCssNameMapping()aracılığıylaBVAVmfveYMlIzgibi class adları üretmek için Closure Stylesheets kullanır. Bunlar her derlemede — bazen haftalık olarak — değişir. -
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.
-
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):
aria-labelöznitelikleri — erişilebilirliğe bağlıdır, nadiren değişirdata-*öznitelikleri — işlev için açıkça eklenirroleöznitelikleri — ARIA rolleri anlamsaldır- Metin tabanlı seçiciler — görünen içeriği eşler
- Alt dize class eşleşmesi — örn.
[class*="price"] - 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.
![]()
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şım | Kurulum Süresi | Kod Gereksinimi | Anti-Bot Yönetimi | Zamanlama | Maliyet |
|---|---|---|---|---|---|
| Kendin yap Playwright (bu rehber) | 1–2 saat | Python (orta seviye) | Manuel yapılandırma | Manuel (cron) | Ücretsiz + proxy maliyeti |
| SerpApi Google Flights uç noktası | 15 dk | Yalnızca API çağrıları | Yönetiliyor | API üzerinden | ~$/ay 50+ |
| Thunderbit Chrome Uzantısı | 2 dk | Yok | Bulut kazıma | Yerleş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.

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 Plan | Notlar |
|---|---|---|---|
| SerpApi | Ayda $75–$3.750+ | Ayda 250 arama | Doğrudan Google Flights JSON’u (hukuki inceleme altında) |
| Kiwi Tequila | Ücretsiz (affiliate modeli) | Sınırsız | Startuplar ve testler için en iyi seçenek |
| Amadeus | Kullandıkça öde | Ayda 2.000 istek | 400+ havayolu, rezervasyon yeteneği |
| Skyscanner | Özel fiyatlandırma | Onay gerekir | 52 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-labelve metin tabanlı seçiciler kullanın, çıktınızı doğrulayın ve bakım takvimi oluşturun scheduleveya 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


