Rakip fiyatlarını, kampanyaları ya da kamuya açık katalogları takip etmek için web kazıma (web scraping) çok güçlü bir araç. Ama iyi bir kazıyıcı sadece veriyi çeken değil, siteye yük bindirmeyen, kurallara uyan ve bozulduğunda kendini belli eden kazıyıcıdır. Bu yazıda Python ile işe yarar ve sorumlu bir kazıyıcının temel parçalarını anlatıyorum.
1. Önce kuralları okuyun
Başlamadan önce sitenin kullanım koşullarına ve robots.txt dosyasına bakın. Bir API ya da veri dışa aktarma seçeneği varsa her zaman onu tercih edin. robots.txt kontrolü Python’un standart kütüphanesiyle yapılabilir:
from urllib import robotparser
rp = robotparser.RobotFileParser()
rp.set_url("https://www.ornek-magaza.com/robots.txt")
rp.read()
url = "https://www.ornek-magaza.com/kategori/sut-urunleri"
if not rp.can_fetch("FiyatTakipBotu", url):
raise SystemExit("Bu sayfanın taranmasına izin verilmiyor.")
bekleme = rp.crawl_delay("FiyatTakipBotu") or 2 # saniye
CAPTCHA, giriş duvarı ya da bot korumasıyla karşılaşırsanız bunu “aşılacak bir engel” değil, sitenin “istemiyorum” demesi olarak okuyun ve durun.
2. Sayfa statikse requests yeterli
Fiyatlar HTML içinde geliyorsa tarayıcı açmaya gerek yok; requests ve BeautifulSoup çok daha hızlı ve hafiftir. Kendinizi tanıtan bir User-Agent kullanın ve istekler arasında bekleyin:
import time
import requests
from bs4 import BeautifulSoup
oturum = requests.Session()
oturum.headers["User-Agent"] = "FiyatTakipBotu/1.0 (+https://www.atilayberber.com)"
def sayfa_getir(url):
yanit = oturum.get(url, timeout=20)
yanit.raise_for_status()
time.sleep(bekleme)
return BeautifulSoup(yanit.text, "html.parser")
3. JavaScript ile yükleniyorsa Selenium 4
Ürünler sayfa açıldıktan sonra JavaScript ile yükleniyorsa Selenium gerekir. Selenium 4’te eski find_element_by_* metotları kaldırıldı; artık By ile çalışılıyor. time.sleep yerine açık bekleme (explicit wait) kullanmak hem daha hızlı hem daha güvenilirdir:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
secenekler = webdriver.ChromeOptions()
secenekler.add_argument("--headless=new")
surucu = webdriver.Chrome(options=secenekler) # Selenium Manager sürücüyü kendisi bulur
try:
surucu.get(url)
WebDriverWait(surucu, 15).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".urun-kart"))
)
kartlar = surucu.find_elements(By.CSS_SELECTOR, ".urun-kart")
for kart in kartlar:
ad = kart.find_element(By.CSS_SELECTOR, ".urun-ad").text
fiyat = kart.find_element(By.CSS_SELECTOR, ".urun-fiyat").text
finally:
surucu.quit()
4. Türkçe fiyatları doğru okuyun
“1.249,90 TL” gibi bir metni float‘a çevirmeye çalışmak hem hata verir hem de kuruş hassasiyetini bozar. Para birimi için Decimal kullanın:
from decimal import Decimal, InvalidOperation
import re
def fiyat_oku(metin: str) -> Decimal | None:
temiz = re.sub(r"[^\d,\.]", "", metin) # "1.249,90"
temiz = temiz.replace(".", "").replace(",", ".") # "1249.90"
try:
return Decimal(temiz)
except InvalidOperation:
return None
fiyat_oku("1.249,90 TL") # Decimal('1249.90')
5. Veriyi toplu yazın
Her ürün için ayrı ayrı INSERT ve commit yapmak yavaştır. Satırları biriktirip toplu yazın; SQL Server kullanıyorsanız pyodbc‘nin fast_executemany özelliği büyük fark yaratır. Bağlantı ve imleçleri her zaman kapatın:
import pyodbc
from contextlib import closing
with closing(pyodbc.connect(BAGLANTI_METNI)) as baglanti:
with closing(baglanti.cursor()) as imlec:
imlec.fast_executemany = True
imlec.executemany(
"INSERT INTO dbo.Fiyat (Kaynak, UrunAdi, Fiyat, Tarih) VALUES (?, ?, ?, SYSDATETIME())",
satirlar,
)
baglanti.commit()
6. Bozulduğunda haberiniz olsun
- Her çalıştırmada kaç ürün çekildiğini kaydedin; sayı birden düşerse büyük ihtimalle sitenin HTML yapısı değişmiştir.
- Sayfalamada aynı ürünün iki kez gelmesine karşı ürün kodu ya da URL ile tekilleştirme yapın.
- Seçicileri (CSS sınıfları) kodun içine dağıtmak yerine tek bir yapılandırma bölümünde tutun; site değiştiğinde tek yerden güncellersiniz.
Kazıma işin sadece ilk adımı. Asıl değer, bu veriyi düzenli olarak bir veritabanına yazıp Power BI gibi bir araçla zaman içindeki değişimi görünür kılmakta.
Sık yapılan hatalar
- 429 yanıtını görmezden gelmek: Site “Too Many Requests” (429) dönüyorsa yavaşlamanızı istiyordur.
Retry-Afterbaşlığına uyun ve beklemeyi her denemede artırın; hemen tekrar denemeyin. - Kırılgan seçiciler: Uzun XPath zincirleri ya da otomatik üretilmiş sınıf adları ilk tasarım değişikliğinde bozulur. Mümkünse sabit kimlikler,
data-*öznitelikleri ya da sayfadaki yapılandırılmış veri (JSON-LD) kullanın. - Hata durumunda sessizce devam etmek: Fiyatı okunamayan ürünü
0olarak yazmak raporu bozar. Okunamayanları ayrı kaydedin ve sayılarını izleyin. - Kişisel veri toplamak: Yorumlar, kullanıcı adları gibi kişisel verileri toplamayın. Fiyat takibi için ürün ve fiyat bilgisi yeterlidir; kişisel veri KVKK kapsamına girer.
Sık sorulan sorular
Web kazıma yasal mı?
Bu bir hukuki görüş değil; ama genel çerçeve şu: kamuya açık veriyi, sitenin kullanım koşullarına ve robots.txt kurallarına uyarak, siteye yük bindirmeden ve kişisel veri toplamadan çekmek çok daha düşük risklidir. Emin değilseniz site sahibinden izin isteyin ya da varsa resmi API’yi kullanın.
Kazıyıcıyı nasıl düzenli çalıştırırım?
Windows’ta Görev Zamanlayıcı, Linux’ta cron yeterlidir. Her çalıştırmanın başlangıç, bitiş ve çekilen kayıt sayısını bir log tablosuna yazarsanız sorunları erkenden fark edersiniz. Fiyat değişimlerini SQL Server’da LAG ile hesaplayıp Power BI’da görselleştirebilirsiniz.
İlgili yazılar
- SQL Server’da Pencere Fonksiyonları: Fiyat değişimini LAG ile hesaplamak
- Power BI’da Tarih Tablosu: Neden Şart, Nasıl Kurulur?
- T-SQL’de RegEx ile ürün adlarını temizlemek
HABERDAR OL
Yeni rehberler, kategorilere ayrılmış tek bir e-postada.
Her pazartesi, o hafta yayımlanan yazılar konu başlıklarına göre derlenmiş olarak gelen kutunda. Yeni yazı yoksa e-posta da yok.

1 yorum