Geçen hafta TripAdvisor üzerinden üç Avrupa şehrindeki yaklaşık 200 tesisin otel puanlarını ve yorum sayılarını çekmeye çalıştım. İlk denemem — varsayılan başlıklarla çalışan basit bir requests.get() — her istekte dümdüz 403 Forbidden döndürdü. Tek bir işe yarar veri baytı bile alamadım.
TripAdvisor, seyahat alanındaki en zengin açık veri kaynaklarından biri: 1 milyardan fazla yorum, 8 milyonu aşan işletme kaydı ve ayda yaklaşık 460 milyon tekil ziyaretçi. Yıllık seyahat harcamalarının $60 milyar üzerindeki kısmını etkiliyor. Peki bu veriyi programatik olarak almak? İşte işin zor tarafı burada başlıyor. TripAdvisor; DataDome bot tespiti, Cloudflare WAF, TLS fingerprinting ve JavaScript zorlukları gibi katmanlı bir savunma sistemi kullanıyor ve çoğu acemi kazıma girişimini daha ilk adımda durduruyor. Bu rehber, keşke elimde olsaydı dediğim tek kaynak: üç Python kazıma yaklaşımının kafa kafaya karşılaştırması (artı kod yazmadan kullanılabilecek bir seçenek), her yöntem için tam kod, yapılandırılmış anti-bot sorun giderme bölümü ve oteller, restoranlar ve turistik yerler genelinde yeniden kullanılabilecek kalıplar. İster Python’a yeni başlamış olun ister deneyimli bir geliştirici, bu rehber size boşuna yaşanmış birçok 403 hatasını kurtaracak.
Kod Yazmak İstemiyor musunuz? TripAdvisor’ı Kolay Yoldan Kazıyın
Bir şeyi en baştan açık söyleyeyim. "Python ile TripAdvisor kazıma" diye arayanların büyük kısmı aslında kod yazmaya meraklı değil. Onların istediği şey, hızlıca tabloya düşen veri — otel adları, puanlar, yorum sayıları, fiyatlar. Eğer siz de onlardan biriyseniz, çok daha kısa bir yol var.
Thunderbit, bizim geliştirdiğimiz yapay zekâ destekli bir Chrome uzantısı; herhangi bir TripAdvisor sayfasını okuyabilir ve hangi sütunların çıkarılması gerektiğini otomatik olarak önerebilir. İş akışı gerçekten iki tıklama kadar basit:
- Bir TripAdvisor listeleme sayfasını açın (ör. "Paris’teki Oteller" sonuçları).
- Thunderbit kenar çubuğunda "AI Suggest Fields" seçeneğine tıklayın. Yapay zekâ sayfayı tarar ve Otel Adı, Puan, Yorum Sayısı, Fiyat ve Konum gibi sütunlar önerir.
- "Scrape" butonuna tıklayın. Thunderbit sayfadaki tüm listelemelerden veriyi çeker — daha fazla sonuç gerekiyorsa sayfalama işlemini de otomatik yapar.
- Veriyi Excel, Google Sheets, Airtable veya Notion’a aktarın. Tüm planlarda dışa aktarma ücretsizdir.
Thunderbit, herhangi bir yapılandırma değişikliği yapmadan oteller, restoranlar ve turistik yerler arasında çalışır — yapay zekâ sayfadaki içeriğe göre kendini uyarlar. Sayfalı sonuçlarda "Next" düğmelerini ve sonsuz kaydırmayı otomatik algılar. Üstelik gerçek Chrome tarayıcınızın içinde çalıştığı için oturum çerezlerinizi ve tarayıcı fingerprint’inizi kullanır; bu da bot tespitine karşı doğal bir avantaj sağlar.
Bunu Thunderbit Chrome Extension ile deneyebilirsiniz — ücretsiz katman ayda 6 sayfa verir; iş akışını test etmek için fazlasıyla yeterli.
Programatik kontrol, özel ayrıştırma mantığı ya da 10.000+ sayfa kazıma planınız varsa, Python doğru seçimdir. Okumaya devam edin.
Neden TripAdvisor’ı Python ile Kazımalısınız?
TripAdvisor verisinin doğrudan ve ölçülebilir bir iş etkisi vardır. Cornell University tarafından yapılan bir çalışmada, bir otelin 100 puanlık Global Review Index değerinde 1 puanlık artışın, ortalama günlük oda fiyatında %0,89 ve müsait oda başına gelirde %1,42 artışa yol açtığı bulundu. ScienceDirect üzerindeki başka bir çalışma ise TripAdvisor puanında dışsal 1 yıldızlık artışın, ortalama bir otel için yıllık gelire 55.000–75.000 dolar eklediğini gösterdi. Yorumlar sadece gösteriş metriği değildir — doğrudan gelir üretirler.
Farklı ekipler TripAdvisor verisini şu şekilde kullanır:
| Kullanım Senaryosu | Kimler İçin Faydalı | Gerekli Veri |
|---|---|---|
| Otel rakip analizi | Otel zincirleri, gelir yöneticileri | Puanlar, fiyatlar, yorum hacmi, olanaklar |
| Restoran pazar araştırması | Restoran grupları, gıda markaları | Mutfak türleri, fiyat aralıkları, yorum duyarlılığı |
| Turistik yer trend takibi | Tur operatörleri, turizm kurulları | Popülerlik sıralamaları, mevsimsel desenler |
| Duygu analizi | Araştırmacılar, veri analistleri | Tam yorum metni, yıldız puanları, tarihler |
| Lead generation | Satış ekipleri, seyahat acenteleri | İşletme adları, iletişim bilgileri, konumlar |
Peki neden özellikle Python? Üç neden var. Birincisi, ekosistem: BeautifulSoup, Selenium, Playwright, Scrapy, httpx, pandas — Python’ın kazıma ve veri analizi kütüphaneleri diğer dillerdeki muadillerine göre daha olgun. İkincisi, web kazıma geliştiricilerinin %71,7’si Python kullanıyor; bu da daha fazla topluluk desteği, daha çok StackOverflow cevabı ve daha güncel rehberler demek. Üçüncüsü, iş akışı avantajı: BeautifulSoup ile kazıyıp pandas ile temizleyebilir, Hugging Face Transformers ile duygu analizi yapabilir ve panolar oluşturabilirsiniz — hepsi tek dilde. Bağlam değiştirme derdi yok.
TripAdvisor’ı Python ile Kazımanın Üç Yolu (Karşılaştırmalı)
Rakip rehberlerin çoğu tek bir yöntemi seçip onun üzerinden gider. Oysa siz kod yazmadan önce karar vermeye çalışıyorsanız bunun pek faydası yok. İşte keşke biri bana önceden verseydi dediğim karşılaştırma tablosu:
| Yaklaşım | Hız | JS Desteği | Bot Engeline Direnç | Karmaşıklık | En Uygun Olduğu Durum |
|---|---|---|---|---|---|
requests + BeautifulSoup | ⚡ Hızlı (~120–200 sayfa/dk ham) | ❌ Yok | ⚠️ Düşük | Kolay | Statik listeleme sayfaları, küçük ölçekli projeler |
| Selenium / Headless Tarayıcı | 🐢 Yavaş (~8–20 sayfa/dk) | ✅ Tam | ⚠️ Orta | Orta | Dinamik içerik, "Read more" tıklamaları, çerez banner’ları |
| Gizli JSON / GraphQL API | ⚡⚡ En hızlı (~200–600 sayfa/dk ham) | N/A | ✅ Daha yüksek | Zor | Büyük ölçekli yorum/otel çıkarımı |
| Kod yazmadan (Thunderbit) | ⚡ Hızlı | ✅ Yerleşik | ✅ Yerleşik | En kolay | Kod yazmayanlar, hızlı tek seferlik dışa aktarımlar |
Birkaç önemli not var. Bu ham hızlar teoriktir — TripAdvisor’ın hız limitleri (IP başına yaklaşık dakikada 10–15 istek) gerçek verimi, yaklaşım ne olursa olsun, kabaca IP başına dakikada 10 sayfaya indirir. Gizli JSON yöntemi, tek istekte daha fazla veri aldığı için toplam istek sayısını azaltır ve hız limitine daha az maruz kalır. Selenium, gerçek dünyadaki ölçümlerde istek tabanlı yöntemlerden yaklaşık 5 kat yavaştır; ancak butonlara tıklamanız veya JavaScript render etmeniz gerekiyorsa tek seçenektir.
Bu rehberin geri kalanı, üç Python yönteminin tamamını tam kodla anlatıyor. Durumunuza uyanı seçin ya da yöntemleri birleştirin (ben çoğu zaman listeleme sayfalarında requests+BS4, detay sayfalarında ise gizli JSON kullanıyorum).
Python Ortamınızı Hazırlayın
Başlamadan önce ortamı hazırlayalım. Python 3.10+ gerekiyor (ben 3.12 veya 3.13 öneriyorum — büyük paketlerin hepsi sorunsuz destekliyor).
Hepsini tek seferde kurun:
pip install requests beautifulsoup4 selenium httpx parsel pandas curl-cffi
Paket notları:
requests(2.33.1) — HTTP istekleri, Python 3.10+ gerekirbeautifulsoup4(4.14.3) — HTML ayrıştırmaselenium(4.43.0) — Tarayıcı otomasyonu, Python 3.10+ gerekirhttpx(0.28.1) — Async HTTP istemcisiparsel(1.11.0) — CSS/XPath seçiciler (BS4’ten daha hafif)pandas(3.0.2) — Veri dışa aktarma, Python 3.11+ gerekircurl_cffi(0.15.0) — TLS fingerprint taklidi (Cloudflare aşmak için kritik)
ChromeDriver: Selenium kullanıyorsanız güzel haber — Selenium 4.6+ ile Selenium Manager, doğru ChromeDriver ikili dosyasını otomatik indirip önbelleğe alır. Elle kurulum gerekmez. Sürüm eşleştirmesini dinamik yaptığı için Chrome sürüm uyumsuzluğu derdi yaşamazsınız.
Sanal ortam (önerilir):
python -m venv tripadvisor-scraper
source tripadvisor-scraper/bin/activate # macOS/Linux
tripadvisor-scraper\Scripts\activate # Windows
Yöntem 1: Requests ve BeautifulSoup ile TripAdvisor Kazıma
Bu en basit yöntemdir. İhtiyacınız olan verinin statik HTML içinde bulunduğu listeleme sayfaları için çok iyi çalışır (otel arama sonuçları, restoran listeleri). Tarayıcı yok, JavaScript render yok, minimum kaynak kullanımı.
TripAdvisor URL Kalıplarını Anlamak
TripAdvisor URL’leri kategoriye göre öngörülebilir kalıplar izler:
- Oteller:
https://www.tripadvisor.com/Hotels-g{locationId}-{Location_Name}-Hotels.html - Restoranlar:
https://www.tripadvisor.com/Restaurants-g{locationId}-{Location_Name}.html - Turistik yerler:
https://www.tripadvisor.com/Attractions-g{locationId}-Activities-{Location_Name}.html
Sayfalama, URL’ye eklenen oa (offset anchors) parametresiyle yapılır. Her sayfada 30 sonuç gösterilir:
-
- sayfa: temel URL (
oaparametresi yok)
- sayfa: temel URL (
-
- sayfa:
Hotels-g187768-oa30-Italy-Hotels.html
- sayfa:
-
- sayfa:
Hotels-g187768-oa60-Italy-Hotels.html
- sayfa:
Yorum sayfalarında ofset parametresi or olur ve 10’ar 10’ar artar:
-
- sayfa:
Reviews-or0-Hotel_Name.html
- sayfa:
-
- sayfa:
Reviews-or10-Hotel_Name.html
- sayfa:
Yorumları tüm dillerde almak için URL’ye ?filterLang=ALL ekleyin.
Gerçekçi Başlıklarla İstek Gönderme
TripAdvisor başlıkları oldukça agresif kontrol eder. Varsayılan Python başlıklarıyla gelen bir istek anında engellenir. Gerçek bir Chrome tarayıcısını taklit etmeniz gerekir:
import requests
import time
import random
session = requests.Session()
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Referer": "https://www.tripadvisor.com/",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
"Sec-CH-UA-Mobile": "?0",
"Sec-CH-UA-Platform": '"Windows"',
}
session.headers.update(headers)
url = "https://www.tripadvisor.com/Hotels-g187147-Paris_Ile_de_France-Hotels.html"
response = session.get(url)
print(f"Status: {response.status_code}")
print(f"İçerik uzunluğu: {len(response.text)} karakter")
Kritik detay: TripAdvisor, User-Agent ile Sec-CH-UA istemci ipuçlarının birbiriyle tutarlı olmasını doğrular. User-Agent içinde Chrome 135 yazıp Sec-CH-UA içinde Chrome 120 derseniz, işaretlenirsiniz. Her zaman tek tek başlıkları değil, tam başlık setlerini birlikte döndürün.
BeautifulSoup ile Listelemeleri Ayrıştırma
Başarılı bir yanıt aldıktan sonra veriyi BeautifulSoup ile çıkarabilirsiniz. TripAdvisor, sık değişen CSS sınıf adları yerine daha kararlı olan data-automation ve data-test-attribute niteliklerini kullanır:
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, "html.parser")
# Tüm otel kartlarını bul
cards = soup.select('div[data-test-attribute="location-results-card"]')
hotels = []
for card in cards:
# Otel adı
title_el = card.select_one('div[data-automation="hotel-card-title"]')
name = title_el.get_text(strip=True) if title_el else None
# Detay sayfası bağlantısı
link_el = card.select_one('div[data-automation="hotel-card-title"] a')
link = "https://www.tripadvisor.com" + link_el["href"] if link_el else None
# Puan
rating_el = card.select_one('[data-automation="bubbleRatingValue"]')
rating = rating_el.get_text(strip=True) if rating_el else None
# Yorum sayısı
review_el = card.select_one('[data-automation="bubbleReviewCount"]')
review_count = review_el.get_text(strip=True).replace(",", "").split()[0] if review_el else None
hotels.append({
"name": name,
"rating": rating,
"review_count": review_count,
"url": link,
})
print(f"Bu sayfada {len(hotels)} otel bulundu")
for h in hotels[:3]:
print(h)
Seçiciler hakkında not: TripAdvisor, her site güncellemesinde değişen obfuscation’lı CSS sınıfları (FGwzt, yyzcQ gibi) kullanır. data-automation ve data-test-target nitelikleri çok daha stabildir. Her zaman sınıf adları yerine veri niteliklerini tercih edin.
Sayfalama ile Baş Etme
Birden fazla sayfa kazımak için, istekler arasında makul bir gecikmeyle ofset parametresi üzerinde döngü kurun:
import pandas as pd
all_hotels = []
base_url = "https://www.tripadvisor.com/Hotels-g187147-oa{offset}-Paris_Ile_de_France-Hotels.html"
for page in range(5): # İlk 5 sayfa
offset = page * 30
url = base_url.format(offset=offset) if page > 0 else "https://www.tripadvisor.com/Hotels-g187147-Paris_Ile_de_France-Hotels.html"
response = session.get(url)
if response.status_code != 200:
print(f"{page + 1}. sayfa: {response.status_code} durumu alındı, durduruluyor.")
break
soup = BeautifulSoup(response.text, "html.parser")
cards = soup.select('div[data-test-attribute="location-results-card"]')
for card in cards:
title_el = card.select_one('div[data-automation="hotel-card-title"]')
name = title_el.get_text(strip=True) if title_el else None
rating_el = card.select_one('[data-automation="bubbleRatingValue"]')
rating = rating_el.get_text(strip=True) if rating_el else None
review_el = card.select_one('[data-automation="bubbleReviewCount"]')
review_count = review_el.get_text(strip=True).replace(",", "").split()[0] if review_el else None
all_hotels.append({"name": name, "rating": rating, "review_count": review_count})
print(f"{page + 1}. sayfa: {len(cards)} otel bulundu")
time.sleep(random.uniform(3, 7)) # Hız limitinden kaçınmak için rastgele gecikme
df = pd.DataFrame(all_hotels)
print(f"\nToplam kazınan otel sayısı: {len(df)}")
time.sleep(random.uniform(3, 7)) önemli. TripAdvisor’ın hız limiti eşiği IP başına kabaca dakikada 10–15 istek civarındadır. Bunun üzerine çıkmak CAPTCHA’ları veya 429 hatalarını tetikler.
Bu Yöntemin Sınırlamaları
Peki bu yöntem ne zaman yetersiz kalır? Requests+BS4 yaklaşımı şu durumlarda başarısız olur:
- TripAdvisor JavaScript ile render edilen içerik sunuyorsa (bazı arama sonuçları JS gerektirir)
- Yorum metni "Read more" butonunun arkasında kısaltılmışsa
- Anti-bot önlemleri JavaScript challenge veya CAPTCHA seviyesine yükselirse
- Yalnızca istemci tarafında render edildikten sonra görünen veriye ihtiyacınız varsa (fiyatlar, müsaitlik)
Bu senaryolarda Selenium’a (Yöntem 2) veya gizli JSON yöntemine (Yöntem 3) geçmeniz gerekir.
Yöntem 2: Selenium ile TripAdvisor Kazıma (Headless Tarayıcı)
Selenium gerçek bir tarayıcı açar; yani JavaScript’i render edebilir, butonlara tıklayabilir, çerez onay banner’larını yönetebilir ve dinamik içerikle etkileşime girebilir. Bedeli mi? Yaklaşık 5 kat daha yavaş olması ve tarayıcı başına 300–500MB RAM kullanması.
Selenium’u Anti-Detection Ayarlarıyla Yapılandırma
Varsayılan haliyle Selenium kolayca tespit edilir. TripAdvisor’ın fingerprint sistemi bunu anında yakalar. Otomasyon bayraklarını devre dışı bırakmanız gerekir:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument("--headless=new") # Yeni headless modu kullan (Chrome 112+)
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--window-size=1920,1080")
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
driver = webdriver.Chrome(options=options)
# navigator içindeki webdriver özelliğini kaldır
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})
Bu TripAdvisor için yeterli mi? Küçük ölçekli kazımada (50 sayfanın altında), bu kurulum residential proxy’lerle birlikte genellikle çalışır. Daha büyük hacimlerde undetected-chromedriver veya nodriver gerekebilir — TripAdvisor’ın DataDome koruması, vanilla Selenium’un taklit edemediği TLS fingerprint’ler dahil her istek için 1.000’den fazla sinyali analiz eder.
Selenium ile Otel Arama Sonuçlarını Kazıma
import time
import random
url = "https://www.tripadvisor.com/Hotels-g187147-Paris_Ile_de_France-Hotels.html"
driver.get(url)
# Otel kartlarının yüklenmesini bekle
wait = WebDriverWait(driver, 15)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-test-attribute="location-results-card"]')))
# Çerez onay penceresini işle (varsa)
try:
cookie_btn = driver.find_element(By.ID, "onetrust-accept-btn-handler")
cookie_btn.click()
time.sleep(1)
except:
pass # Çerez penceresi yok
# Otel verilerini çıkar
cards = driver.find_elements(By.CSS_SELECTOR, 'div[data-test-attribute="location-results-card"]')
hotels = []
for card in cards:
try:
name = card.find_element(By.CSS_SELECTOR, 'div[data-automation="hotel-card-title"]').text
except:
name = None
try:
rating = card.find_element(By.CSS_SELECTOR, '[data-automation="bubbleRatingValue"]').text
except:
rating = None
try:
reviews = card.find_element(By.CSS_SELECTOR, '[data-automation="bubbleReviewCount"]').text
except:
reviews = None
hotels.append({"name": name, "rating": rating, "review_count": reviews})
print(f"{len(hotels)} otel kazındı")
for h in hotels[:3]:
print(h)
Bu sayfa benim makinemde tek bir sayfa için yaklaşık 8 saniye sürdü — requests+BS4 ile 1 saniyenin altına kıyasla. Yüzlerce sayfa kazırken bu 8 kat fark çok hızlı büyür.
"Read More" Butonlarını Açma ve Tam Yorumları Kazıma
Yorum sayfaları uzun yorumları "Read more" butonunun arkasında kısaltır. Selenium bunu tıklayabilir:
review_url = "https://www.tripadvisor.com/Hotel_Review-g187147-d188726-Reviews-Le_Marais_Hotel-Paris_Ile_de_France.html"
driver.get(review_url)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-reviewid]')))
time.sleep(2)
# Tüm "Read more" butonlarına tıkla
read_more_buttons = driver.find_elements(By.XPATH, '//button//*[contains(text(), "Read more")]/..')
for btn in read_more_buttons:
try:
driver.execute_script("arguments[0].click();", btn)
time.sleep(0.3)
except:
pass
# Yorumları çıkar
review_elements = driver.find_elements(By.CSS_SELECTOR, 'div[data-reviewid]')
reviews = []
for rev in review_elements:
try:
title = rev.find_element(By.CSS_SELECTOR, 'div[data-test-target="review-title"]').text
except:
title = None
try:
body = rev.find_element(By.CSS_SELECTOR, 'q.IRsGHoPm span').text
except:
try:
body = rev.find_element(By.CSS_SELECTOR, 'p.partial_entry').text
except:
body = None
try:
rating_class = rev.find_element(By.CSS_SELECTOR, 'div[data-test-target="review-rating"] span').get_attribute("class")
# Yıldız puanı "ui_bubble_rating bubble_50" gibi bir sınıfta kodlanır = 5.0
rating_num = [c for c in rating_class.split() if "bubble_" in c][0].replace("bubble_", "")
rating = int(rating_num) / 10
except:
rating = None
reviews.append({"title": title, "body": body, "rating": rating})
print(f"{len(reviews)} yorum kazındı")
Selenium’a Proxy Rotasyonu Eklemek
Sürekli kazıma için proxy rotasyonu gerekir. selenium-wire Ocak 2024’ten beri kullanımdan kalktığı için Chrome’un yerleşik proxy desteğini kullanın:
# Kimlik doğrulama gerektirmeyen proxy ile
proxy = "http://your-proxy-address:port"
options.add_argument(f"--proxy-server={proxy}")
# Kimlik doğrulamalı proxy’ler için Chrome uzantısı veya Selenium 4 BiDi protokolü kullanın
Proxy’leri programatik olarak döndürmek için, her istek grubu için farklı proxy ile yeni bir driver örneği oluşturun. Şık olmayabilir, ama güvenilirdir.
Yöntem 3: Gizli JSON Yöntemi (HTML Ayrıştırmayı Tamamen Atla)
Çoğu rehber bu yöntemi tamamen atlar; bu da yazık — çünkü üç yöntem arasında en hızlı ve en temiz olanı budur. TripAdvisor, yapılandırılmış veriyi HTML sayfalarının içine doğrudan JSON olarak gömer — <script> etiketleri içinde pageManifest ve urqlCache gibi JavaScript değişkenleri olarak. Bu JSON’u çıkarmak size daha temiz veri (sayısal puanlar, ISO formatında tarihler), daha az istek ve JavaScript render ihtiyacı olmadan çalışma avantajı sağlar.
Sayfa Kaynağında Gömülü JSON’u Bulma
Ana fikir şu: Sayfayı almak için basit bir requests.get() kullanabilir, ardından JavaScript’i hiç render etmeden ham HTML’den JSON’u çıkarabilirsiniz.
import requests
import re
import json
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Referer": "https://www.tripadvisor.com/",
"Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
"Sec-CH-UA-Mobile": "?0",
"Sec-CH-UA-Platform": '"macOS"',
}
url = "https://www.tripadvisor.com/Hotel_Review-g188590-d194317-Reviews-NH_City_Centre_Amsterdam.html"
response = requests.get(url, headers=headers)
# pageManifest JSON bloğunu çıkar
match = re.search(r"pageManifest:({.+?})};", response.text)
if match:
page_data = json.loads(match.group(1))
print("pageManifest verisi bulundu")
print(f"Anahtarlar: {list(page_data.keys())[:10]}")
Değişken adını nasıl kendin bulursun: Herhangi bir TripAdvisor otel sayfasını Chrome’da aç, sağ tıkla → Sayfa Kaynağını Görüntüle, sonra Ctrl+F ile pageManifest veya urqlCache ya da aggregateRating ara. Veri orada, ayrıştırılmayı bekliyor.
JSON’u Ayrıştırma ve Yapılandırılmış Veriyi Çıkarma
TripAdvisor ayrıca application/ld+json schema.org verisi de gömer; bunu çıkarmak daha da kolaydır:
from parsel import Selector
sel = Selector(text=response.text)
# JSON-LD yapılandırılmış veriyi çıkar
json_ld_scripts = sel.xpath("//script[@type='application/ld+json']/text()").getall()
for script in json_ld_scripts:
data = json.loads(script)
if isinstance(data, dict) and data.get("@type") in ["Hotel", "Restaurant", "TouristAttraction"]:
print(f"Ad: {data.get('name')}")
print(f"Puan: {data.get('aggregateRating', {}).get('ratingValue')}")
print(f"Yorum Sayısı: {data.get('aggregateRating', {}).get('reviewCount')}")
print(f"Fiyat Aralığı: {data.get('priceRange')}")
print(f"Adres: {data.get('address', {}).get('streetAddress')}")
print(f"Koordinatlar: {data.get('geo', {}).get('latitude')}, {data.get('geo', {}).get('longitude')}")
break
JSON-LD verisi statik HTML içine gömülüdür ve JavaScript render etmeyi gerektirmez. İşletme adını, genel puanı, yorum sayısını, adresi, koordinatları, fiyat aralığını ve fotoğraf URL’lerini — tek bir HTML etiketini bile ayrıştırmadan — elde edebilirsiniz.
Daha zengin veri için (tek tek yorumlar, puan dağılımları, olanak listeleri) urqlCache nesnesine ihtiyacınız vardır:
# Detaylı yorum verisi için urqlCache'i çıkar
cache_match = re.search(r'"urqlCache"\s*:\s*({.+?})\s*,\s*"redux"', response.text)
if cache_match:
cache_data = json.loads(cache_match.group(1))
# Yorum verisini bulmak için cache içinde dolaş
for key, value in cache_data.items():
if "reviews" in str(value).lower()[:100]:
reviews_data = json.loads(value.get("data", "{}")) if isinstance(value, dict) else None
if reviews_data:
print(f"Yorum cache girdisi bulundu: {key[:50]}...")
break
Tam JSON yolları TripAdvisor ön yüzünü güncellediğinde zaman zaman değişebilir; ancak genel yapı — özet veri için JSON-LD, detaylı veri için urqlCache — yıllardır oldukça stabildir.
TripAdvisor’ın GraphQL API’sini Tersine Mühendislikle Kullanma (İleri Seviye)
Büyük ölçekli çıkarım için TripAdvisor’ın GraphQL uç noktaları yapılandırılmış veriyi doğrudan döndürür. Bu en hızlı yöntemdir, fakat bakım maliyeti en yüksektir.
import httpx
import random
import string
def generate_request_id():
"""X-Requested-By başlık değeri oluştur"""
random_chars = ''.join(random.choices(string.ascii_letters + string.digits, k=180))
return f"TNI1625!{random_chars}"
# Paris'te otel arama
search_payload = [{
"variables": {
"request": {
"query": "hotels in Paris",
"limit": 10,
"scope": "WORLDWIDE",
"locale": "en-US",
"scopeGeoId": 1,
"searchCenter": None,
"types": ["LOCATION", "QUERY_SUGGESTION", "RESCUE_RESULT"],
"locationTypes": ["GEO", "AIRPORT", "ACCOMMODATION", "ATTRACTION", "EATERY", "NEIGHBORHOOD"]
}
},
"extensions": {
"preRegisteredQueryId": "84b17ed122fbdbd4"
}
}]
graphql_headers = {
"Content-Type": "application/json",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.9",
"Origin": "https://www.tripadvisor.com",
"Referer": "https://www.tripadvisor.com/Hotels",
"X-Requested-By": generate_request_id(),
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
}
with httpx.Client() as client:
response = client.post(
"https://www.tripadvisor.com/data/graphql/ids",
json=search_payload,
headers=graphql_headers
)
if response.status_code == 200:
results = response.json()
print(json.dumps(results, indent=2)[:1000])
else:
print(f"GraphQL isteği başarısız oldu: {response.status_code}")
Yorumları GraphQL ile çekmek için:
review_payload = [{
"variables": {
"locationId": 194317, # NH City Centre Amsterdam
"offset": 0,
"limit": 20,
"filters": {},
"sortType": None,
"sortBy": "date",
"language": "en",
"doMachineTranslation": False,
"photosPerReviewLimit": 3
},
"extensions": {
"preRegisteredQueryId": "ef1a9f94012220d3"
}
}]
with httpx.Client() as client:
response = client.post(
"https://www.tripadvisor.com/data/graphql/ids",
json=review_payload,
headers=graphql_headers
)
if response.status_code == 200:
data = response.json()
reviews = data[0]["data"]["locations"][0]["reviewListPage"]["reviews"]
total = data[0]["data"]["locations"][0]["reviewListPage"]["totalCount"]
print(f"Toplam yorum: {total}")
for r in reviews[:3]:
print(f" [{r['rating']}/5] {r['title']} - {r['createdDate']}")
Önemli uyarı: preRegisteredQueryId değerleri (arama için 84b17ed122fbdbd4, yorumlar için ef1a9f94012220d3 gibi) TripAdvisor yeniden dağıtım yaptığında bozulabilir. O zaman istekleriniz sessizce başarısız olur. Sorgu kimliklerini yeniden bulmak için tarayıcı DevTools içindeki ağ isteklerini izlemeniz gerekir.
Bu Yöntem Neden Proxy İhtiyacını Azaltır?
Matematik basit. Requests+BS4 ile 100 otel detay sayfasını kazımak 100 istek gerektirir. Gizli JSON yöntemiyle her istek, tek bir sayfa yüklemesinden ihtiyacınız olan tüm veriyi döndürür — yorum açma veya dinamik içerik yükleme için ek isteğe gerek kalmaz. GraphQL ile tek bir API çağrısı aynı anda 20 yorum döndürebilir. Daha az istek = hız limitine daha az maruz kalma = proxy rotasyonuna daha az ihtiyaç. Küçük ve orta ölçekli projelerde (1.000 sayfanın altında), makul gecikmeler eklerseniz hiç proxy’ye ihtiyaç duymayabilirsiniz.
Tek Bir Yeniden Kullanılabilir Script ile Otel, Restoran ve Turistik Yerleri Kazıyın
Rakip rehberlerin beşte dördü yalnızca otelleri ele alıyor. Oysa TripAdvisor’ın üç ana içerik kategorisi var ve URL kalıpları ile veri alanları kategoriler arasında farklılaşıyor. İşte üçünü de ele alan tek bir fonksiyon nasıl kurulur.
Kategori Başına Mevcut Veri Alanları
| Alan | Oteller | Restoranlar | Turistik Yerler |
|---|---|---|---|
| Ad | ✅ | ✅ | ✅ |
| Puan | ✅ | ✅ | ✅ |
| Yorum sayısı | ✅ | ✅ | ✅ |
| Fiyat/Fiyat aralığı | ✅ | ✅ | Bazen |
| Adres | ✅ | ✅ | ✅ |
| Mutfak türü | ❌ | ✅ | ❌ |
| Süre/Tur türü | ❌ | ❌ | ✅ |
| Olanaklar | ✅ | ❌ | ❌ |
| Koordinatlar | ✅ | ✅ | ✅ |
Yeniden Kullanılabilir scrape_tripadvisor() Fonksiyonu Oluşturma
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random
import re
import json
def scrape_tripadvisor(category, location_id, location_name, num_pages=3):
"""
TripAdvisor listelemelerini oteller, restoranlar veya turistik yerler için kazır.
Args:
category: "hotels", "restaurants" veya "attractions"
location_id: TripAdvisor geo ID (ör. Paris için "187147")
location_name: URL dostu isim (ör. "Paris_Ile_de_France")
num_pages: Kazınacak sayfa sayısı
"""
url_patterns = {
"hotels": "https://www.tripadvisor.com/Hotels-g{geo}-oa{offset}-{name}-Hotels.html",
"restaurants": "https://www.tripadvisor.com/Restaurants-g{geo}-oa{offset}-{name}.html",
"attractions": "https://www.tripadvisor.com/Attractions-g{geo}-oa{offset}-Activities-{name}.html",
}
first_page_patterns = {
"hotels": "https://www.tripadvisor.com/Hotels-g{geo}-{name}-Hotels.html",
"restaurants": "https://www.tripadvisor.com/Restaurants-g{geo}-{name}.html",
"attractions": "https://www.tripadvisor.com/Attractions-g{geo}-Activities-{name}.html",
}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Referer": "https://www.tripadvisor.com/",
"Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
"Sec-CH-UA-Mobile": "?0",
"Sec-CH-UA-Platform": '"Windows"',
}
session = requests.Session()
session.headers.update(headers)
all_items = []
for page in range(num_pages):
offset = page * 30
if page == 0:
url = first_page_patterns[category].format(geo=location_id, name=location_name)
else:
url = url_patterns[category].format(geo=location_id, offset=offset, name=location_name)
response = session.get(url)
if response.status_code != 200:
print(f" {page + 1}. sayfa: {response.status_code} durumu, durduruluyor.")
break
soup = BeautifulSoup(response.text, "html.parser")
cards = soup.select('div[data-test-attribute="location-results-card"]')
for card in cards:
item = {"category": category}
title_el = card.select_one('div[data-automation="hotel-card-title"]') or card.select_one('a[data-automation]')
item["name"] = title_el.get_text(strip=True) if title_el else None
rating_el = card.select_one('[data-automation="bubbleRatingValue"]')
item["rating"] = rating_el.get_text(strip=True) if rating_el else None
review_el = card.select_one('[data-automation="bubbleReviewCount"]')
item["review_count"] = review_el.get_text(strip=True) if review_el else None
all_items.append(item)
print(f" {page + 1}. sayfa: {len(cards)} öğe bulundu")
time.sleep(random.uniform(3, 7))
return pd.DataFrame(all_items)
# Kullanım örnekleri
print("=== Paris'teki Oteller ===")
hotels_df = scrape_tripadvisor("hotels", "187147", "Paris_Ile_de_France", num_pages=2)
print(hotels_df.head())
print("\n=== Roma'daki Restoranlar ===")
restaurants_df = scrape_tripadvisor("restaurants", "187791", "Rome_Lazio", num_pages=2)
print(restaurants_df.head())
print("\n=== Barselona'daki Turistik Yerler ===")
attractions_df = scrape_tripadvisor("attractions", "187497", "Barcelona_Catalonia", num_pages=2)
print(attractions_df.head())
Tek fonksiyon, üç kategori, sıfır kod tekrarı. TripAdvisor bir seçiciyi değiştirirse, bunu tek bir yerde düzeltirsiniz.
TripAdvisor Sizi Engellediğinde Ne Yapmalısınız? (Anti-Bot Sorun Giderme)
Bu, TripAdvisor kazımaya başladığımda en çok ihtiyaç duyduğum bölümdü ve rakip rehberlerin yapılandırılmış şekilde sunmadığı kısım da bu. TripAdvisor, DataDome’u (günde 5+ trilyon veri noktası analizi) ve Cloudflare WAF’i birlikte kullanıyor. En yaygın hata türleri için bir teşhis tablosu hazırladım:
| Belirti | Olası Neden | Çözüm |
|---|---|---|
| HTTP 403 yanıtı | Eksik veya şüpheli başlıklar; Cloudflare JS challenge | Gerçekçi User-Agent, Accept-Language, Referer ve Sec-CH-UA başlıkları kullanın. Başlık tutarlılığını sağlayın. |
| Veri yerine CAPTCHA sayfası | Hız limiti veya tarayıcı fingerprinting | Residential proxy kullanın, rastgele gecikmeler ekleyin (istekler arasında 2–7 saniye) |
| Boş HTML veya boş sayfa gövdesi | JavaScript requests ile render edilmedi | Selenium’a geçin veya sayfa kaynağındaki gizli JSON’dan çıkarın |
| Kısmi yorumlar / "Read more" açılmıyor | İçerik tıklama olayında yükleniyor | Selenium ile tıklayın ya da gömülü JSON bloğundan çıkarın |
| Yorumlar yalnızca tek dilde | Dil parametresi eksik | Yorum URL’sine ?filterLang=ALL ekleyin |
| N sayfasından sonra veri yüklenmiyor | Oturum bazlı hız limiti | Oturumları döndürün, partiler arasında çerezleri temizleyin |
| HTTP 1020 Access Denied | Cloudflare IP/ASN engeli | Veri merkezi proxy’sinden residential proxy’ye geçin |
| Challenge döngüsü (sonsuz CAPTCHA) | Bozuk çerez kalıcılığı | Önce ana sayfayı ziyaret ederek oturumları ısıtın; cookie jar’ı koruyun |
Üstel Geri Çekilme ile Tekrar Deneme Mantığı
Rakip makalelerin hiçbiri bunu gerçekten kodla göstermiyor. İşte yeniden kullanılabilir bir tekrar deneme fonksiyonu:
import time
import random
import requests
def fetch_with_retry(session, url, max_retries=4, base_delay=2, max_delay=60):
"""
Üstel geri çekilme ve jitter ile URL al.
Her denemede User-Agent döndürür.
"""
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
]
for attempt in range(max_retries):
# Her yeniden denemede User-Agent değiştir
if attempt > 0:
session.headers["User-Agent"] = random.choice(user_agents)
try:
response = session.get(url, timeout=30)
if response.status_code == 200:
return response
if response.status_code == 429:
# Varsa Retry-After başlığına uy
retry_after = int(response.headers.get("Retry-After", base_delay * (2 ** attempt)))
print(f" Hız sınırına takıldı (429). {retry_after}s bekleniyor...")
time.sleep(retry_after)
continue
if response.status_code in (403, 503):
wait = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
print(f" {response.status_code} alındı. {attempt + 1}/{max_retries} denemesi {wait:.1f}s içinde...")
time.sleep(wait)
continue
# Diğer hata kodları — yeniden deneme
print(f" {url} için beklenmeyen durum {response.status_code}")
return response
except requests.exceptions.Timeout:
wait = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
print(f" Zaman aşımı. {attempt + 1}/{max_retries} denemesi {wait:.1f}s içinde...")
time.sleep(wait)
print(f" {url} için {max_retries} denemenin tümü tükendi")
return None
Başlıkları, Proxy’leri ve Oturumları Döndürme
Sürekli kazıma için, başlık setlerinden oluşan bir havuz tutun ve bunları birlikte döndürün:
import random
HEADER_SETS = [
{
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
"Sec-CH-UA-Platform": '"Windows"',
},
{
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
"Sec-CH-UA-Platform": '"macOS"',
},
{
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
"Sec-CH-UA": '"Google Chrome";v="134", "Not-A.Brand";v="8", "Chromium";v="134"',
"Sec-CH-UA-Platform": '"Windows"',
},
]
PROXY_LIST = [
"http://user:pass@residential-proxy-1:port",
"http://user:pass@residential-proxy-2:port",
# Daha fazla residential proxy ekleyin
]
def get_rotated_session():
"""Döndürülmüş başlık ve proxy ile yeni bir oturum oluştur."""
session = requests.Session()
# Rastgele bir başlık seti seç
header_set = random.choice(HEADER_SETS)
base_headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Referer": "https://www.tripadvisor.com/",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-CH-UA-Mobile": "?0",
}
base_headers.update(header_set)
session.headers.update(base_headers)
# Rastgele proxy seç
if PROXY_LIST:
proxy = random.choice(PROXY_LIST)
session.proxies = {"http": proxy, "https": proxy}
return session
Proxy türü önemlidir. Veri merkezi proxy’leri TripAdvisor tarafından neredeyse anında engellenir (HTTP 1020 Access Denied). Sürekli kazıma için residential proxy’ler zorunludur — tüketici ISP’leri üzerinden yönlendirilirler ve gerçek kullanıcıdan ayırt edilmeleri zordur. Sağlayıcıya göre GB başına 2,50–8,40 dolar ödemeyi bekleyin.
Kazıdığınız TripAdvisor Verisini Dışa Aktarma ve Saklama
Veriyi aldıktan sonra, kullanılabilir bir formata dönüştürmek oldukça kolaydır.
CSV Dışa Aktarma (En Yaygın Yöntem)
import pandas as pd
df = pd.DataFrame(all_hotels)
df.to_csv("tripadvisor_hotels_paris.csv", index=False, encoding="utf-8-sig")
print(f"{len(df)} satır CSV'ye aktarıldı")
encoding='utf-8-sig' önemlidir — CSV’yi Excel’de açtığınızda Latin dışı karakterlerin (Fransızca aksanlar, Çince karakterler vb.) doğru görünmesini sağlar.
JSON Dışa Aktarma (İç İçe Veriler İçin)
Otellerin altında yorumlar gibi iç içe veri varsa, JSON hiyerarşiyi korur:
# Hiyerarşik yapı
hotel_data = {
"property_id": "d194317",
"name": "NH City Centre Amsterdam",
"rating": 4.0,
"reviews": [
{"title": "Great location", "rating": 5, "date": "2025-03-15", "text": "..."},
{"title": "Average stay", "rating": 3, "date": "2025-03-10", "text": "..."},
]
}
# Düz analiz için json_normalize kullanın
flat_reviews = pd.json_normalize(
hotel_data,
record_path="reviews",
meta=["property_id", "name"]
)
flat_reviews.to_csv("reviews_flat.csv", index=False)
İlişkisel Veri İçin İki Dosyalı Yaklaşım
Büyük veri kümelerinde iki CSV dosyası kullanırım:
hotels.csv— Tesis başına bir satır (düz)reviews.csv— Yorum başına bir satır,property_idyabancı anahtar olarak
Bu yapı, pandas’ta birleştirmeyi, veritabanına yüklemeyi veya BI araçlarına aktarmayı kolaylaştırır.
Tüm bu dışa aktarma mantığıyla uğraşmak istemiyorsanız, Thunderbit ile kazınan veriyi doğrudan Excel, Google Sheets, Airtable veya Notion’a aktarabilirsiniz — hepsi ücretsiz, üstelik kod gerektirmez. Teknik olmayan ekip arkadaşlarınızla sonuç paylaşmanız gerektiğinde çok kullanışlıdır.
Sorumlu ve Verimli TripAdvisor Kazıma İpuçları
Sorumlu kazıma için altı kısa madde:
robots.txtdosyasını kontrol edin: TripAdvisor’ın robots.txt dosyası AI eğitim botlarını (GPTBot, ClaudeBot vb.) tamamen engeller. Standart tarayıcılar ise seçici yol kısıtlamalarıyla karşılaşır.tripadvisor.com/robots.txtadresinden inceleyin.- Gecikme ekleyin: İstekler arasında 3–7 saniye güvenli bir aralıktır. Dakikada 10–15 isteğin üstüne çıkmak hız sınırlamasını tetikler.
- Yalnızca herkese açık veriyi kazıyın. Kısıtlı içeriğe erişmek için giriş yapmayın.
- Veriyi güvenli saklayın ve kişisel bilgi (yorumcu adları vb.) işliyorsanız GDPR/CCPA’ya uyun.
- Ticari ölçekte veri gerekiyorsa TripAdvisor’ın resmi API’sini değerlendirin. Developer Portal, işletme detayları ile birlikte lokasyon başına en fazla 5 yorum ve 5 fotoğrafa erişim sunar — sınırlı ama yasal ve stabildir.
- Hukuki bağlamın farkında olun: AB Mahkemesi Ryanair kararı (Aralık 2025), AB genelinde hizmet şartlarına dayalı kazıma yasaklarını güçlendirdi. TripAdvisor’ın Kullanım Şartları açıkça kazımayı yasaklar. Sorumlu şekilde ve kendi riskinizle kazıyın.
Sonuç
Tablonun özeti bu.
- Requests + BeautifulSoup en basit yoldur. Statik listeleme sayfalarında çalışır, minimum kurulum ister ve hızlıdır. 100 sayfadan az kazıyorsanız ve JavaScript ile render edilen içerik gerekmiyorsa buradan başlayın.
- Selenium, requests’in yapamadığı her şeyi halleder: dinamik içerik, "Read more" butonları, çerez banner’ları. 5 kat daha yavaştır ve kaynak tüketimi yüksektir; ama sayfayla etkileşim kurmanız gerekiyorsa tek seçenektir.
- Gizli JSON / GraphQL, en temiz ve en hızlı yaklaşımdır. HTML ayrıştırmadan yapılandırılmış veri sağlar, istek sayısını azaltır (dolayısıyla proxy ihtiyacını da), ve analize hazır formatlarda veri döndürür. Ancak TripAdvisor veri yapısını değiştirdiğinde önceden tersine mühendislik ve ara sıra bakım gerektirir.
Yeniden kullanılabilir scrape_tripadvisor() fonksiyonu otelleri, restoranları ve turistik yerleri kapsar. İkinci bir eğitime ihtiyacınız olmamalı.
Ve eğer rehberin ortasında kod yazmanın size göre olmadığına karar verirseniz — ya da sadece gün sonuna kadar bir tabloda 50 otele ihtiyacınız varsa — Thunderbit’in Chrome uzantısı bunu yapay zekâ destekli alan algılama, otomatik sayfalama ve Excel ya da Google Sheets’e ücretsiz dışa aktarma ile iki tıklamada yapabilir. Python gerekmez.
Daha derine inmek isterseniz, Thunderbit blog ve YouTube kanalımızda daha fazla kazıma anlatımı bulabilirsiniz.
SSS
1. TripAdvisor kazımak yasal mı?
TripAdvisor’ın Kullanım Şartları kazımayı açıkça yasaklar. Ancak mahkemeler genelde, giriş duvarının arkasında olmayan herkese açık verilerin kazınmasının ABD’de Computer Fraud and Abuse Act’i ihlal etmediğine hükmetmiştir. Yine de 2025 AB Mahkemesi Ryanair kararı, Avrupa’da hizmet şartlarına dayalı kısıtlamaları güçlendirdi. Yalnızca herkese açık veriyi kazıyın, robots.txt kurallarına uyun, telifli içeriği yeniden yayımlamayın ve veriyi ticari olarak kullanacaksanız hukuk danışmanına başvurun.
2. TripAdvisor’ı Python olmadan kazıyabilir miyim?
Evet. Thunderbit gibi kod yazmadan kullanılan araçlar, yapay zekâ destekli alan algılama ve otomatik sayfalama ile TripAdvisor’ı doğrudan tarayıcınızdan kazıyabilir. Tarayıcı uzantıları, Google Sheets eklentileri veya ticari kazıma API’leri de kullanabilirsiniz. Python size en fazla kontrolü ve esnekliği verir, ama tek seçenek değildir.
3. TripAdvisor kazırken engellenmemek için ne yapmalıyım?
Temel taktikler: gerçekçi ve tutarlı başlıklar kullanın (özellikle User-Agent ve Sec-CH-UA), residential proxy döndürün (veri merkezi IP’leri hemen engellenir), istekler arasında 3–7 saniyelik rastgele gecikmeler ekleyin, toplam istek sayısını azaltmak için gizli JSON yöntemini kullanın, üstel geri çekilme ile tekrar deneme mantığı uygulayın ve derin sayfalara geçmeden önce ana sayfayı ziyaret ederek oturumları ısıtın.
4. TripAdvisor’dan hangi verileri kazıyabilirim?
Oteller, restoranlar ve turistik yerler — isimler, puanlar, yorum sayıları, fiyat aralıkları, adresler, koordinatlar, olanaklar (oteller), mutfak türleri (restoranlar), tur süreleri (turistik yerler) ve tek tek puanları ve tarihleriyle tam yorum metinleri dahil. Gizli JSON ve GraphQL yaklaşımları, istek başına en zengin veriyi döndürür.
5. Günde TripAdvisor’dan kaç sayfa kazıyabilirim?
Tek bir IP ve makul gecikmelerle: yaklaşık 600–1.000 sayfa/gün. 20 dönen residential proxy ile: istek tabanlı yaklaşımlarda yaklaşık 200.000–300.000 sayfa/gün. Selenium daha yavaştır — proxy başına günde 8.000–12.000 sayfa bekleyin. Gizli JSON/GraphQL yaklaşımı, istek başına en fazla veriyi verdiği için aynı bilgiyi almak adına çok daha az sayfa gerekebilir.
Daha Fazla Öğrenin


