Python ile Otel Fiyatlarını Otomatik Takip Ederek Akıllı Seyahat Planlama
Otel fiyatları, seyahat planlarımızın en önemli bileşenlerinden biridir ve genellikle sürekli dalgalanma gösterir. En iyi fırsatı yakalamak, doğru zamanda doğru kararı vermek, pek çok gezgin için adeta bir strateji oyunu haline gelmiştir. Peki ya bu karmaşık oyunu otomatikleştirebilseydik? Python programlama dilinin gücünü kullanarak, istediğiniz herhangi bir şehirdeki otel fiyatlarını düzenli olarak takip edip bir e-tabloya (spreadsheet) otomatik olarak kaydederek, akıllı seyahat kararları almanın kapılarını aralayabiliriz. Bu makalede, otel fiyatlarını izlemek için adım adım bir Python tabanlı çözüm oluşturmayı, temelden ileri düzeye kadar tüm detaylarıyla ele alacağız. Veri kazıma (web scraping) tekniklerinden, elde edilen veriyi düzenlemeye ve e-tabloya kaydetmeye kadar tüm süreci keşfedeceksiniz. Böylece, hem zamandan tasarruf edecek hem de bütçenize en uygun konaklama seçeneklerini kolayca belirleyebileceksiniz.
Otel Fiyat Takibi Neden Önemli? Temel Kavramlara Giriş
Otel fiyatları, mevsimsel değişiklikler, özel etkinlikler, talep yoğunluğu, hatta son dakika kampanyaları gibi birçok faktöre bağlı olarak sürekli olarak değişir. Bir hafta önce gördüğünüz bir fiyatın, bugün çok daha yüksek veya şaşırtıcı derecede düşük olabildiğini fark etmişsinizdir. Bu dinamik yapı, özellikle bütçe dostu seyahatler planlayanlar veya iş seyahatleri için en uygun konaklama seçeneklerini arayanlar için büyük bir zorluk teşkil eder. Manuel olarak her gün farklı otel sitelerini kontrol etmek hem zaman alıcı hem de yorucudur. İşte tam bu noktada, otomasyonun ve veri kazımanın önemi ortaya çıkar.
Peki, bu otomasyonu nasıl sağlayacağız? Temelinde iki ana kavram yatıyor: Web kazıma (Web Scraping) ve API’ler. Web kazıma, bir web sitesindeki verileri otomatik olarak çekme işlemidir. Bu işlem genellikle web sayfalarının HTML yapısını analiz ederek ve belirli etiketler veya sınıflar aracılığıyla istenen bilgileri (otel adı, fiyat, puan, konum vb.) ayrıştırarak (parsing) gerçekleştirilir. Diğer yandan, API (Uygulama Programlama Arayüzü), bir uygulamanın başka bir uygulama ile iletişim kurmasını sağlayan tanımlı bir dizi kuraldır. Bazı otel rezervasyon siteleri, geliştiricilerin fiyat ve müsaitlik verilerine programatik olarak erişmesine izin veren API’ler sunar. Ancak, tüm sitelerin API’si yoktur veya API erişimi kısıtlı olabilir. Bu durumda, web kazıma vazgeçilmez bir araç haline gelir.
Bu projede kullanacağımız temel Python kütüphaneleri şunlardır:
requests: Web sayfalarının HTML içeriğini çekmek için kullanılır. HTTP istekleri (GET, POST vb.) yapmamızı sağlar.BeautifulSoup: Çekilen HTML içeriğini ayrıştırmak ve istediğimiz verileri kolayca bulmak için tasarlanmış bir kütüphanedir. HTML ve XML belgelerini gezilebilir bir yapıya dönüştürür.Selenium: JavaScript ile dinamik olarak yüklenen içeriklere sahip web sitelerinden veri kazımak için kullanılır. Gerçek bir tarayıcıyı (Chrome, Firefox vb.) programatik olarak kontrol etmemizi sağlar.Pandas: Veri analizi ve manipülasyonu için güçlü bir kütüphanedir. Kazınan verileri düzenli bir DataFrame (veri çerçevesi) yapısında tutmamıza ve işlememize olanak tanır.openpyxl: Python’dan Excel dosyalarını (.xlsxuzantılı) okumak ve yazmak için kullanılır. Pandas’ınto_excel()metodu genellikle bu kütüphaneyi arka planda kullanır.
Veri kazıma yaparken hukuki ve etik boyutları da göz önünde bulundurmak önemlidir. Her sitenin kendine ait kullanım koşulları (terms of service) ve robots.txt dosyası bulunur. robots.txt dosyası, bir web sitesinin hangi bölümlerinin otomatik tarayıcılar tarafından ziyaret edilip edilemeyeceğini belirtir. Bu kurallara uymak, hem yasal sorunlardan kaçınmak hem de siteye aşırı yük bindirmemek adına kritik öneme sahiptir. Amacımız, siteye zarar vermek değil, sadece herkese açık olan bilgileri akıllıca kullanarak kişisel fayda sağlamaktır.
Adım Adım Otel Fiyatlarını Kazıma: Bir Şehir Örneği
Otel fiyatlarını kazıma sürecinin ilk ve en kritik adımı, hedef web sitesini seçmek ve yapısını anlamaktır. Bu makalede, herhangi bir spesifik otel rezervasyon sitesi yerine genel bir senaryo üzerinden ilerleyeceğiz. Genellikle, otel arama sonuçları sayfaları, otel adını, fiyatını, puanını ve konumunu içeren benzer HTML yapılarına sahiptir. Bu bilgiler, bir web tarayıcısının “İncele” (Inspect Element) özelliği kullanılarak kolayca tespit edilebilir.
Öncelikle, requests kütüphanesi ile hedef sayfanın HTML içeriğini çekmemiz gerekiyor. Web siteleri genellikle bot trafiğini engellemek için bazı önlemler alır. Bu nedenle, bir “User-Agent” (Kullanıcı Aracısı) başlığı (header) ekleyerek kendimizi gerçek bir tarayıcı gibi göstermek iyi bir uygulamadır. Ardından, çekilen HTML içeriğini BeautifulSoup ile ayrıştırarak istediğimiz verileri bulacağız.
Şimdi, İstanbul için otel fiyatlarını kazıdığımızı varsayan basit bir senaryo üzerinden ilerleyelim. Amacımız, otel adlarını ve fiyatlarını bulmak olsun. Unutmayın, aşağıdaki kod örneğindeki CSS sınıfları (örneğin, hotel-name, hotel-price) tamamen örnek amaçlıdır ve gerçek bir web sitesinin yapısına göre değişiklik gösterecektir. Kendi projenizde, hedef sitenin HTML yapısını dikkatlice incelemeniz gerekecektir.
import requests
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime
def otel_fiyatlarini_kazima(sehir, giris_tarihi, cikis_tarihi):
# Bu URL, gerçek bir otel sitesinin arama URL'si gibi düşünülmelidir.
# Tarih ve şehir parametreleri, sitenin URL yapısına göre ayarlanmalıdır.
# Örneğin: https://www.example.com/search?city=Istanbul&checkin=2023-10-26&checkout=2023-10-27
url = f"https://www.example.com/hotels?city={sehir}&checkin={giris_tarihi}&checkout={cikis_tarihi}"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Accept-Language": "tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7"
}
otel_listesi = []
try:
response = requests.get(url, headers=headers, timeout=10) # 10 saniye zaman aşımı
response.raise_for_status() # HTTP hataları için istisna fırlatır (4xx veya 5xx)
soup = BeautifulSoup(response.text, 'html.parser')
# Bu kısım, hedef sitenin HTML yapısına göre tamamen değişecektir.
# Aşağıdaki örnekler, yaygın olarak kullanılan etiket ve sınıf yapılarını temsil eder.
# Tüm otel kartlarını veya listeleme öğelerini bulma
# Örneğin, her otel bilgisi bir 'div' etiketi içinde 'hotel-card' sınıfına sahip olabilir.
hotel_cards = soup.find_all('div', class_='hotel-card')
if not hotel_cards:
print(f"{sehir} için otel kartları bulunamadı. Lütfen CSS seçicileri kontrol edin.")
# Alternatif bir seçici denenebilir veya hata mesajı verilebilir.
# Örneğin, bazı sitelerde oteller 'li' etiketinde olabilir.
hotel_cards = soup.find_all('li', class_='search-result-item')
if not hotel_cards:
print(f"{sehir} için hiçbir otel bilgisi bulunamadı.")
return []
for card in hotel_cards:
otel_adi = "N/A"
fiyat = "N/A"
puan = "N/A"
konum = "N/A"
# Otel Adı
name_element = card.find('h3', class_='hotel-name') # veya 'a', 'span' içinde olabilir
if name_element:
otel_adi = name_element.text.strip()
# Fiyat
price_element = card.find('span', class_='price-value') # veya 'div', 'strong' içinde olabilir
if price_element:
fiyat = price_element.text.strip()
# Fiyatı sayısal bir değere dönüştürme (örneğin, "1.500 TL" -> 1500)
try:
fiyat = float(fiyat.replace('.', '').replace(',', '.').replace('TL', '').strip())
except ValueError:
pass # Dönüştürme başarısız olursa string olarak kalır
# Puan
rating_element = card.find('span', class_='hotel-rating') # veya 'div' içinde 'data-rating' niteliği
if rating_element:
puan = rating_element.text.strip()
# Konum (genellikle otel adının altında veya ayrı bir div içinde)
location_element = card.find('div', class_='hotel-location')
if location_element:
konum = location_element.text.strip()
otel_listesi.append({
'Şehir': sehir,
'Giriş Tarihi': giris_tarihi,
'Çıkış Tarihi': cikis_tarihi,
'Otel Adı': otel_adi,
'Fiyat': fiyat,
'Puan': puan,
'Konum': konum,
'Kazıma Tarihi': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
})
except requests.exceptions.HTTPError as errh:
print(f"HTTP Hatası: {errh}")
except requests.exceptions.ConnectionError as errc:
print(f"Bağlantı Hatası: {errc}")
except requests.exceptions.Timeout as errt:
print(f"Zaman Aşımı Hatası: {errt}")
except requests.exceptions.RequestException as err:
print(f"Genel İstek Hatası: {err}")
except Exception as e:
print(f"Beklenmeyen bir hata oluştu: {e}")
return otel_listesi
# Örnek kullanım:
# istanbul_otelleri = otel_fiyatlarini_kazima("Istanbul", "2024-11-15", "2024-11-17")
# if istanbul_otelleri:
# df = pd.DataFrame(istanbul_otelleri)
# print(df.head())
Yukarıdaki kod bloğunda, otel_fiyatlarini_kazima adında bir fonksiyon tanımladık. Bu fonksiyon, belirli bir şehir ve tarih aralığı için otel verilerini kazımayı amaçlar. requests.get() ile web sayfasının içeriğini çektikten sonra, BeautifulSoup nesnesi oluşturulur. Ardından, soup.find_all() metodu ile otel bilgilerini içeren ana konteynerler (örneğin, <div class="hotel-card">) bulunur. Her bir otel kartının içinde, otel adı, fiyat, puan ve konum gibi spesifik bilgiler, ilgili HTML etiketleri ve CSS sınıfları kullanılarak çekilir. Çekilen her otel bilgisi bir sözlük (dictionary) olarak otel_listesi‘ne eklenir. Fiyat gibi sayısal veriler, daha sonra analiz için uygun formata dönüştürülmeye çalışılır. Bu yaklaşım, çoğu statik web sitesi için oldukça etkilidir. Ancak, JavaScript ile dinamik olarak yüklenen içeriklerde bu yöntem yetersiz kalabilir. İşte bu noktada Selenium devreye girer.
Dinamik İçerik ve Sayfalama Yönetimi: Selenium Kullanımı
Günümüz web sitelerinin çoğu, kullanıcı deneyimini zenginleştirmek için JavaScript kullanır. Bu, sayfa içeriğinin bir kısmının veya tamamının, sayfa ilk yüklendiğinde HTML içinde bulunmadığı, ancak daha sonra JavaScript kodları çalıştırılarak tarayıcıda dinamik olarak oluşturulduğu anlamına gelir. Örneğin, bir otel arama sayfasında aşağı kaydırdıkça (scroll ettikçe) yeni otel sonuçlarının yüklenmesi veya bir butona tıklandığında içeriğin değişmesi gibi durumlar dinamik içeriğe örnek teşkil eder. requests ve BeautifulSoup kütüphaneleri, yalnızca ilk HTML yanıtını alabildiği için bu tür dinamik içerikleri kazımakta yetersiz kalır.
Bu sorunu çözmek için Selenium kütüphanesini kullanırız. Selenium, aslında web uygulamalarını test etmek için tasarlanmış bir araçtır, ancak bir tarayıcıyı programatik olarak kontrol edebilme yeteneği sayesinde web kazıma için de oldukça güçlü bir araç haline gelmiştir. Selenium ile gerçek bir web tarayıcısını (Chrome, Firefox gibi) başlatabilir, sayfalar arasında gezinebilir, butonlara tıklayabilir, metin kutularına veri girebilir, sayfa içeriğini kaydırabilir ve en önemlisi, JavaScript tarafından oluşturulan tüm içeriğe erişebiliriz.
Selenium kullanmak için öncelikle bir WebDriver’a ihtiyacınız vardır. WebDriver, Selenium’un tarayıcı ile iletişim kurmasını sağlayan köprü yazılımdır. En yaygın kullanılanlar Chrome için ChromeDriver ve Firefox için GeckoDriver’dır. Bu sürücüleri indirip sistem PATH’inize eklemeniz veya betiğinizde yolunu belirtmeniz gerekir.
Şimdi, Selenium ile dinamik bir sayfadan veri çekme ve sayfalama (pagination) işlemini yönetme senaryosunu inceleyelim. Örneğin, bir otel sitesinde “Daha Fazla Göster” butonu olduğunu veya sayfanın otomatik olarak kaydırıldıkça yeni içerik yüklediğini varsayalım:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
import pandas as pd
import time
from datetime import datetime
def dinamik_otel_fiyatlarini_kazima(sehir, giris_tarihi, cikis_tarihi, sayfa_sayisi=3):
# WebDriver yolu (örneğin, ChromeDriver). Kendi yolunuzu belirtin.
# chromedriver.chromium.org/downloads adresinden indirilebilir.
chrome_driver_path = "C:/chromedriver/chromedriver.exe" # Örnek yol
# Chrome seçenekleri
chrome_options = Options()
chrome_options.add_argument("--headless") # Tarayıcıyı görünmez modda çalıştırır (arka planda çalışır)
chrome_options.add_argument("--disable-gpu") # GPU donanım hızlandırmasını devre dışı bırakır (headless için gerekli olabilir)
chrome_options.add_argument("--no-sandbox") # Güvenlik için sandbox'ı devre dışı bırakır (bazı ortamlarda gerekli olabilir)
chrome_options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
chrome_options.add_argument("accept-language=tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7")
service = Service(executable_path=chrome_driver_path)
driver = webdriver.Chrome(service=service, options=chrome_options)
url = f"https://www.example.com/hotels?city={sehir}&checkin={giris_tarihi}&checkout={cikis_tarihi}"
otel_listesi = []
try:
driver.get(url)
# Sayfanın tamamen yüklenmesini beklemek için örtülü bir bekleme ekleyebiliriz.
driver.implicitly_wait(10) # Elementlerin bulunması için maksimum 10 saniye bekle
# Dinamik içerik yüklemesi veya sayfalama yönetimi
for i in range(sayfa_sayisi): # Belirli sayıda sayfa veya "Daha Fazla" butonu için döngü
print(f"Sayfa {i+1} için veri çekiliyor...")
time.sleep(3) # Sayfanın yüklenmesini ve JavaScript'in çalışmasını beklemek için
# Eğer "Daha Fazla Göster" butonu varsa:
try:
load_more_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CLASS_NAME, "load-more-button")) # Örnek CSS sınıfı
)
load_more_button.click()
time.sleep(2) # Butona tıklandıktan sonra yeni içeriğin yüklenmesini bekle
except:
# Buton bulunamazsa veya tıklanamazsa, tüm içerik yüklenmiş demektir.
print("Daha fazla göster butonu bulunamadı veya tüm içerik yüklendi.")
break
# Alternatif olarak, sayfayı aşağı kaydırma (scroll) ile dinamik yükleme:
# driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# time.sleep(3) # Yeni içeriğin yüklenmesini bekle
# Tüm dinamik içerik yüklendikten sonra HTML'i Beautiful Soup ile ayrıştır.
soup = BeautifulSoup(driver.page_source, 'html.parser')
hotel_cards = soup.find_all('div', class_='hotel-card')
if not hotel_cards:
print(f"{sehir} için otel kartları bulunamadı. Lütfen CSS seçicileri kontrol edin.")
hotel_cards = soup.find_all('li', class_='search-result-item')
if not hotel_cards:
print(f"{sehir} için hiçbir otel bilgisi bulunamadı.")
return []
for card in hotel_cards:
otel_adi = "N/A"
fiyat = "N/A"
puan = "N/A"
konum = "N/A"
name_element = card.find('h3', class_='hotel-name')
if name_element:
otel_adi = name_element.text.strip()
price_element = card.find('span', class_='price-value')
if price_element:
fiyat = price_element.text.strip()
try:
fiyat = float(fiyat.replace('.', '').replace(',', '.').replace('TL', '').strip())
except ValueError:
pass
rating_element = card.find('span', class_='hotel-rating')
if rating_element:
puan = rating_element.text.strip()
location_element = card.find('div', class_='hotel-location')
if location_element:
konum = location_element.text.strip()
otel_listesi.append({
'Şehir': sehir,
'Giriş Tarihi': giris_tarihi,
'Çıkış Tarihi': cikis_tarihi,
'Otel Adı': otel_adi,
'Fiyat': fiyat,
'Puan': puan,
'Konum': konum,
'Kazıma Tarihi': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
})
except Exception as e:
print(f"Selenium veya web kazıma sırasında bir hata oluştu: {e}")
finally:
driver.quit() # Tarayıcıyı kapat
return otel_listesi
# Örnek kullanım:
# izmir_otelleri = dinamik_otel_fiyatlarini_kazima("Izmir", "2024-12-01", "2024-12-03", sayfa_sayisi=2)
# if izmir_otelleri:
# df_izmir = pd.DataFrame(izmir_otelleri)
# print(df_izmir.head())
Bu kod bloğunda, Selenium ile bir Chrome tarayıcısı başlatılır (--headless argümanı sayesinde görünmez modda). Belirtilen URL’ye gidildikten sonra, sayfanın tamamen yüklenmesi için belirli bir süre beklenir. Ardından, bir döngü içinde “Daha Fazla Göster” butonu aranır ve bulunursa tıklanır. Bu işlem, sayfa içeriğinin tamamen yüklenmesini sağlar. Tüm dinamik içerik yüklendikten sonra, driver.page_source ile sayfanın güncel HTML içeriği alınır ve yine BeautifulSoup ile ayrıştırma işlemi gerçekleştirilir. Bu yöntem, JavaScript tabanlı ve dinamik içeriklere sahip web sitelerinden veri çekmek için çok daha esneklik sunar.
Toplanan Verileri E-Tabloya Kaydetme ve Yönetme
Web kazıma (web scraping) ile elde ettiğimiz ham veriler, genellikle liste veya sözlükler (dictionaries) şeklinde olur. Bu verileri daha anlamlı hale getirmek, analiz etmek ve uzun vadede takip etmek için düzenli bir yapıya, yani bir e-tabloya (spreadsheet) kaydetmemiz gerekir. Python’da bu işlem için Pandas kütüphanesi ve onun DataFrame yapısı biçilmiş kaftandır. Pandas, verileri tablo benzeri bir yapıda tutmamızı ve Excel, CSV gibi çeşitli formatlara kolayca aktarmamızı sağlar.
Kazıdığımız otel verilerini bir Pandas DataFrame‘ine dönüştürdükten sonra, bu verileri bir Excel dosyasına (.xlsx) kaydetmek için to_excel() metodunu kullanabiliriz. Projemizin temel amacı, fiyatları düzenli olarak takip etmek olduğundan, her çalıştırmada yeni verilerin mevcut Excel dosyasına eklenmesini sağlamamız önemlidir. Bu, zaman damgası (timestamp) ile birlikte fiyat değişimlerini izlememize olanak tanır.
Aşağıdaki kod bloğu, kazınan otel verilerini bir DataFrame‘e dönüştürmeyi ve bu verileri mevcut bir Excel dosyasına eklemeyi veya dosya yoksa yeni bir dosya oluşturmayı göstermektedir:
import pandas as pd
from datetime import datetime
def verileri_excel_e_kaydet(otel_verileri, dosya_adi="otel_fiyatlari_takibi.xlsx"):
if not otel_verileri:
print("Kaydedilecek veri bulunamadı.")
return
# Kazınan verilerden bir DataFrame oluştur
yeni_df = pd.DataFrame(otel_verileri)
try:
# Mevcut Excel dosyasını oku
mevcut_df = pd.read_excel(dosya_adi)
# Yeni verileri mevcut verilere ekle
# Bu, her çalıştırmada yeni fiyatların bir önceki günün/saatin fiyatlarının altına eklenmesini sağlar.
guncel_df = pd.concat([mevcut_df, yeni_df], ignore_index=True)
except FileNotFoundError:
# Eğer dosya yoksa, yeni DataFrame'i kullan
guncel_df = yeni_df
except Exception as e:
print(f"Mevcut Excel dosyasını okurken bir hata oluştu: {e}. Yeni dosya oluşturuluyor.")
guncel_df = yeni_df
# DataFrame'i Excel dosyasına kaydet
# index=False, DataFrame indeksini Excel'e yazmamasını sağlar.
guncel_df.to_excel(dosya_adi, index=False)
print(f"Veriler '{dosya_adi}' dosyasına başarıyla kaydedildi. Toplam {len(guncel_df)} kayıt.")
# --- Örnek Kullanım ---
# Bu kısım, bir önceki adımdaki kazıma fonksiyonlarından dönen veriyi simüle eder.
# Örneğin, otel_fiyatlarini_kazima veya dinamik_otel_fiyatlarini_kazima fonksiyonundan gelen bir liste.
ornek_kazilmis_veri = [
{
'Şehir': 'İstanbul',
'Giriş Tarihi': '2024-11-15',
'Çıkış Tarihi': '2024-11-17',
'Otel Adı': 'Grand Hotel İstanbul',
'Fiyat': 2500.0,
'Puan': 8.8,
'Konum': 'Beyoğlu',
'Kazıma Tarihi': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
'Şehir': 'İstanbul',
'Giriş Tarihi': '2024-11-15',
'Çıkış Tarihi': '2024-11-17',
'Otel Adı': 'Bosphorus View Suites',
'Fiyat': 3200.0,
'Puan': 9.2,
'Konum': 'Beşiktaş',
'Kazıma Tarihi': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
'Şehir': 'Ankara',
'Giriş Tarihi': '2024-12-05',
'Çıkış Tarihi': '2024-12-07',
'Otel Adı': 'Ankara Business Hotel',
'Fiyat': 1200.0,
'Puan': 7.9,
'Konum': 'Çankaya',
'Kazıma Tarihi': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
]
# Verileri kaydetme fonksiyonunu çağır
# verileri_excel_e_kaydet(ornek_kazilmis_veri)
# Gerçek kullanımda, kazıma fonksiyonlarından dönen veriyi buraya aktaracaksınız:
# kazilmis_istanbul = otel_fiyatlarini_kazima("Istanbul", "2024-11-15", "2024-11-17")
# verileri_excel_e_kaydet(kazilmis_istanbul)
Bu fonksiyon, önce kazınan verilerden bir Pandas DataFrame‘i oluşturur. Ardından, hedef Excel dosyasının (otel_fiyatlari_takibi.xlsx) zaten var olup olmadığını kontrol eder. Eğer dosya mevcutsa, pd.read_excel() ile mevcut verileri okur ve yeni verileri pd.concat() kullanarak mevcut verilere ekler. Bu sayede, her çalıştırmada yeni fiyatlar, önceki kayıtların altına eklenir ve uzun vadeli bir fiyat takip geçmişi oluşturulur. Eğer dosya mevcut değilse (FileNotFoundError), yeni veriler doğrudan yeni bir Excel dosyası olarak kaydedilir. Son olarak, to_excel(dosya_adi, index=False) metodu ile tüm veriler Excel dosyasına yazılır. index=False parametresi, Pandas’ın otomatik olarak atadığı indeks sütununu Excel dosyasına yazmasını engeller, böylece daha temiz bir görünüm elde edilir.
Bu yöntemle, farklı şehirler, farklı tarihler ve farklı otel sitelerinden topladığınız tüm verileri tek bir merkezi e-tabloda birleştirebilirsiniz. Zaman damgası (Kazıma Tarihi) sütunu sayesinde, herhangi bir otelin fiyatının belirli bir tarihte ne olduğunu kolayca görebilir ve fiyat trendlerini analiz edebilirsiniz. Bu, gerçekten akıllı seyahat planlaması için paha biçilmez bir veri kaynağı oluşturur.
Gelişmiş Teknikler ve Otomasyon İpuçları
Temel otel fiyatı kazıma ve e-tabloya kaydetme mekanizmasını kurduktan sonra, sisteminizi daha sağlam, verimli ve kullanıcı dostu hale getirecek bazı gelişmiş teknikler ve otomasyon ipuçlarına geçebiliriz. Bu ipuçları, projenizin gerçek dünya koşullarında sorunsuz çalışmasını sağlamanın yanı sıra, elde ettiğiniz verilerden daha fazla değer çıkarmanıza yardımcı olacaktır.
Zamanlanmış Görevler ile Otomatik Çalıştırma
Otel fiyatlarını manuel olarak çalıştırmak yerine, betiğinizi belirli aralıklarla (örneğin, günde bir kez, haftada bir kez) otomatik olarak çalışacak şekilde ayarlamak, otomasyonun gerçek gücünü ortaya koyar. Bunun için farklı işletim sistemlerinde kullanabileceğiniz araçlar mevcuttur:
- Linux/macOS:
cron(Cron job) aracı, belirli zamanlarda komutları veya betikleri çalıştırmak için kullanılır. Örneğin, her gün sabah 08:00’de betiğinizi çalıştırmak için bir cron girdisi oluşturabilirsiniz. - Windows: Görev Zamanlayıcısı (Task Scheduler), benzer bir işlevi yerine getirir. Python betiğinizi belirli bir zamanda veya belirli bir olay tetiklendiğinde çalışacak şekilde ayarlayabilirsiniz.
Bu sayede, siz uyurken veya başka işlerle meşgulken sisteminiz arka planda otel fiyatlarını takip etmeye devam eder.
Proxy (Vekil Sunucu) Kullanımı
Web kazıma yaparken, aynı IP adresinden çok sayıda istek göndermek, hedef web sitesi tarafından şüpheli aktivite olarak algılanabilir ve IP adresinizin engellenmesine yol açabilir. Bu durumu aşmak için proxy sunucuları kullanabilirsiniz. Bir proxy sunucusu, sizinle hedef web sitesi arasında bir aracı görevi görür ve isteklerinizin farklı IP adreslerinden geliyormuş gibi görünmesini sağlar. Bu, IP engellemelerini önlemenize yardımcı olur. Ücretsiz proxy’ler genellikle yavaş ve güvenilmez olsa da, ücretli proxy hizmetleri daha istikrarlı ve hızlı çözümler sunar.
CAPTCHA Çözümü
Bazı web siteleri, otomatik botları engellemek için CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) kullanır. Bu, resimdeki metni tanıma, belirli nesneleri seçme veya basit matematiksel işlemler yapma gibi görevler olabilir. CAPTCHA’lar, web kazıma sürecini kesintiye uğratabilir. Basit CAPTCHA’lar için bazı Python kütüphaneleri (örneğin, Pytesseract ile OCR – Optik Karakter Tanıma) denenebilirken, daha karmaşık reCAPTCHA’lar için üçüncü taraf CAPTCHA çözme hizmetleri (örneğin, 2Captcha, Anti-Captcha) veya Selenium ile manuel müdahale gerekebilir.
Hata Yönetimi ve Günlükleme (Logging)
Web siteleri zaman zaman değişebilir, ağ sorunları yaşanabilir veya beklenmedik hatalar ortaya çıkabilir. Betiğinizin bu durumlarla başa çıkabilmesi için sağlam bir hata yönetimi (error handling) ve günlükleme (logging) mekanizması eklemek önemlidir. try-except blokları ile potansiyel hataları yakalayabilir ve logging modülü ile betiğinizin çalışma durumu, karşılaşılan hatalar ve önemli olaylar hakkında bilgi kaydedebilirsiniz. Bu günlükler, sorun giderme ve sisteminizin performansını izleme açısından çok değerlidir.
Veri Görselleştirme ile Fiyat Trendlerini Anlama
E-tablonuzda biriken ham veriler değerli olsa da, bu verilerin arkasındaki hikayeyi görselleştirmek, fiyat trendlerini ve fırsatları daha net görmenizi sağlar. Matplotlib ve Seaborn gibi Python kütüphaneleri ile otel fiyatlarının zaman içindeki değişimini gösteren grafikler (çizgi grafikleri), farklı otellerin fiyat karşılaştırmalarını gösteren çubuk grafikleri veya belirli bir şehirdeki ortalama fiyatları gösteren dağılım grafikleri oluşturabilirsiniz. Bu görselleştirmeler, en uygun rezervasyon zamanını belirlemenize yardımcı olabilir.
Uyarı Sistemleri
En uygun fiyatı kaçırmamak için, otel fiyatı belirli bir eşiğin altına düştüğünde size otomatik olarak bildirim gönderen bir sistem kurabilirsiniz. Python, e-posta göndermek (smtplib), Telegram veya WhatsApp gibi mesajlaşma uygulamaları aracılığıyla bildirimler göndermek için çeşitli kütüphaneler sunar. Bu sayede, fiyat düşüşlerini anında öğrenerek hızlıca harekete geçebilir ve en iyi fırsatları yakalayabilirsiniz.
Bu gelişmiş teknikler, otel fiyat takip sisteminizi sadece bir veri toplama aracından çok daha fazlasına dönüştürür. Daha dayanıklı, daha akıllı ve daha proaktif bir seyahat planlama yardımcısı oluşturmanıza olanak tanır.
Vaka Analizi: Akıllı Bir Seyahat Planlayıcısı Nasıl Olur?
Şimdiye kadar öğrendiğimiz tüm bilgileri bir araya getirerek, gerçek dünya senaryosunda bir “Akıllı Seyahat Planlayıcısı”nın nasıl tasarlanabileceğini ve Python ile nasıl hayata geçirilebileceğini bir vaka analizi üzerinden inceleyelim.
Senaryo: Aylin, sık seyahat eden bir iş insanı. Önümüzdeki altı ay içinde İstanbul, İzmir ve Antalya’ya farklı tarihlerde iş seyahatleri planlıyor. Her şehir için belirli tarihlerde (örneğin, İstanbul için 15-17 Kasım, İzmir için 5-7 Aralık, Antalya için 20-22 Ocak) kalmayı düşünüyor. Aylin, şirket politikaları gereği bütçe dostu konaklama seçenekleri bulmak zorunda ve aynı zamanda yüksek puanlı otelleri tercih ediyor. Farklı otel rezervasyon sitelerindeki fiyatların sürekli değiştiğini bildiği için, en uygun fiyata en iyi oteli bulmakta zorlanıyor. Her gün siteleri tek tek kontrol etmek yerine, otomatik bir sisteme ihtiyacı var.
Çözüm Mimarisi: Aylin için Python tabanlı bir Akıllı Seyahat Planlayıcısı tasarlayabiliriz. Bu sistem aşağıdaki bileşenlerden oluşacaktır:
- Konfigürasyon Dosyası: Hangi şehirlerin, hangi tarihler arasında ve hangi otel sitelerinin takip edileceğini içeren basit bir JSON veya CSV dosyası. Aylin bu dosyayı kolayca güncelleyebilir.
- Veri Kazıma Modülü:
requestsveBeautifulSoupkullanarak statik içerikli sitelerden veri çeker.Seleniumkullanarak dinamik içerikli sitelerden (örneğin, aşağı kaydırıldıkça yeni otellerin yüklendiği siteler) veri çeker.- IP engellemelerini önlemek için bir proxy havuzu kullanır.
- CAPTCHA ile karşılaştığında, e-posta ile Aylin’i bilgilendirir ve manuel müdahale için bekler veya bir CAPTCHA çözme servisi entegre eder.
- Farklı otel sitelerinden (Booking.com, Expedia, Hotels.com gibi) verileri toplar ve her bir site için ayrı ayrıştırma (parsing) kuralları içerir.
- Veri Depolama ve Yönetim Modülü:
- Toplanan tüm otel verilerini (otel adı, fiyat, puan, konum, giriş/çıkış tarihleri, kazıma tarihi, kaynak site) tek bir
Pandas DataFrame‘inde birleştirir. - Bu
DataFrame‘i düzenli olarak (örneğin, her gün) bir ana Excel dosyasına (seyahat_planlayici.xlsx) kaydeder. Mevcut verilere yeni verileri ekler. - İsteğe bağlı olarak, daha büyük veri setleri için SQLite gibi hafif bir veritabanı (database) kullanarak verileri kalıcı olarak saklayabilir.
- Toplanan tüm otel verilerini (otel adı, fiyat, puan, konum, giriş/çıkış tarihleri, kazıma tarihi, kaynak site) tek bir
- Analiz ve Uyarı Modülü:
- Excel dosyasındaki geçmiş verileri kullanarak belirli bir otelin veya şehirdeki ortalama otel fiyatlarının zaman içindeki değişimini analiz eder.
- Aylin’in belirlediği kriterlere (örneğin, “İstanbul’da 8.5 puan üzeri otellerin fiyatı 2000 TL’nin altına düşerse”) uygun bir fiyat bulunduğunda otomatik e-posta veya Telegram bildirimi gönderir.
- En düşük fiyatı sunan otelleri ve ilgili rezervasyon sitelerini belirler.
- Otomasyon Modülü:
- Tüm sistemi (veri kazıma, depolama, analiz, uyarı) her gün sabah 07:00’de otomatik olarak çalıştıracak bir cron job (Linux/macOS) veya Görev Zamanlayıcısı (Windows) kurar.
İşleyiş:
- Aylin,
config.jsondosyasında takip etmek istediği şehirleri, tarihleri ve otel sitelerini tanımlar. - Sistem her sabah otomatik olarak çalışır.
- Veri kazıma modülü, konfigürasyondaki her bir şehir-tarih-site kombinasyonu için ilgili web sitelerini ziyaret eder, otel verilerini çeker.
- Çekilen veriler, merkezi Excel dosyasına veya veritabanına eklenir.
- Analiz modülü, yeni eklenen verileri ve geçmiş verileri karşılaştırarak Aylin’in belirlediği kriterlere uygun fırsatları kontrol eder.
- Eğer bir fırsat (örneğin, İstanbul’daki hedef otelin fiyatı düştü) tespit edilirse, Aylin’e otomatik bir e-posta bildirimi gönderilir.
- Aylin, Excel dosyasını açarak veya bildirimdeki linke tıklayarak en güncel fiyatları ve trendleri görebilir, böylece hızlı ve bilinçli bir karar verebilir.
Bu vaka analizi, Python’ın otomasyon ve veri kazıma yeteneklerinin kişisel seyahat planlamasından kurumsal bütçe yönetimine kadar nasıl geniş bir yelpazede kullanılabileceğini göstermektedir. Bu tür bir sistem, sadece zamandan tasarruf etmekle kalmaz, aynı zamanda daha akıllı ve daha ekonomik seyahat kararları almanızı sağlar.
Sonuç ve Sıkça Sorulan Sorular
Python ile otel fiyatlarını takip etmek ve bu verileri düzenli bir e-tabloya kaydetmek, seyahat planlama sürecinizi tamamen dönüştürebilecek güçlü bir otomasyon çözümüdür. Bu makalede, web kazımanın temel prensiplerinden, statik ve dinamik içerikleri işlemek için requests, BeautifulSoup ve Selenium gibi kütüphanelerin kullanımına, toplanan verileri Pandas ile düzenleyip Excel’e kaydetmeye ve son olarak sisteminizi daha dayanıklı ve akıllı hale getirecek gelişmiş tekniklere kadar geniş bir yelpazeyi ele aldık. Artık, otel fiyatlarındaki dalgalanmaları manuel olarak takip etmek zorunda kalmadan, en iyi fırsatları yakalayabilecek ve seyahat bütçenizi optimize edebileceksiniz. Bu yetenekler, sadece kişisel kullanım için değil, aynı zamanda küçük işletmeler veya seyahat acenteleri için de paha biçilmez bir araç olabilir.
Sıkça Sorulan Sorular
- Tüm otel sitelerinden veri kazıyabilir miyim?
Teorik olarak evet, ancak pratik olarak bazı siteler daha zorlayıcı olabilir. JavaScript yoğun siteler içinSeleniumgibi araçlar gerekirken, bazı siteler çok güçlü bot engelleme mekanizmalarına (CAPTCHA, IP engelleme) sahip olabilir. Ayrıca, her siteninrobots.txtdosyasına ve kullanım koşullarına uymak önemlidir. - IP adresim engellenirse ne yapmalıyım?
IP adresiniz engellenirse, bir proxy (vekil sunucu) hizmeti kullanarak farklı IP adresleri üzerinden istek göndermeyi deneyebilirsiniz. Ayrıca, istekler arasında daha uzun bekleme süreleri (time.sleep()) eklemek veyaUser-Agentbaşlığını düzenli olarak değiştirmek de yardımcı olabilir. - Bu sistemi ne sıklıkla çalıştırmalıyım?
Bu, otel fiyatlarının ne kadar sık değiştiğine ve sizin ne kadar güncel bilgiye ihtiyacınız olduğuna bağlıdır. Günde bir kez çalıştırmak çoğu senaryo için yeterli olabilir. Çok sık çalıştırmak (örneğin, her 15 dakikada bir) web sitesine aşırı yük bindirebilir ve IP engellemelerine yol açabilir. - Sadece Python bilerek bu projeyi yapabilir miyim?
Evet, temel Python bilgisiyle başlayabilir ve bu makaledeki adımları takip ederek projeyi tamamlayabilirsiniz. HTML ve CSS seçicilerini anlama yeteneği de çok yardımcı olacaktır, ancak bu becerileri de süreç içinde öğrenebilirsiniz. - Topladığım verileri ticari amaçla kullanabilir miyim?
Topladığınız verileri ticari amaçla kullanmadan önce, verileri kazıdığınız web sitesinin kullanım koşullarını dikkatlice okumanız ve yasal tavsiye almanız kritik öneme sahiptir. Çoğu web sitesi, verilerinin ticari amaçla izinsiz kullanımına izin vermez. Kişisel kullanım genellikle daha az risk taşır.
#Teknoloji #WebGeliştirme #Python #OtelFiyatları #VeriKazıma
