E-Ticarette Rakip Fiyat Takibi Nasıl Yapılır?

Yayın tarihi:

14 dk okuma

Enver Kaya
Yazar: Enver Kaya
Solda barkodlu ürün eşleştirme kartı, ortada üç ürün küpü taşıyan tarama motoru, sağda düşüşle işaretli fiyat geçmişi satırı

Pazartesi sabahı satış raporunu açıyorsunuz: en çok satan üç üründe sipariş hafta sonu yarıya inmiş. Nedenini öğleden sonra, rakibin sayfasına elle bakınca buluyorsunuz. Cuma akşamı fiyatı indirmiş, siz iki gün boyunca pahalı kalmışsınız. Rakip fiyat takibinin çözdüğü sorun budur: değişikliği satış kaybından değil, değişikliğin kendisinden öğrenmek.

Bu yazıda işi uçtan uca kuruyoruz. Önce verinin nereden gelebileceğini (satıcı API'si, hazır araç, kendi betiğiniz) karşılaştırıyoruz; ardından ürün eşleştirmeyi, hangi fiyatın kaydedileceğini ve tarama sıklığının nasıl hesaplanacağını anlatıyoruz. Geliştiriciler için fiyatı sayfadan okuyan, SQLite'ta geçmiş tutan ve eşik aşılınca uyarı veren, denenmiş bir Python örneği var. Sonda işin sınırları duruyor: site şartları, robots.txt ve rekabet hukuku.

Rakip fiyat takibi hangi adımlardan oluşur?

Fiyat takibi, rakip ürün sayfalarındaki fiyat ve stok bilgisinin düzenli aralıklarla okunup kaydedilmesidir. Tanımın ayrıntısı ve altyapı tarafı fiyat takibi çözümü sayfamızda; burada işin nasıl kurulduğuna bakıyoruz. Aracınız ne olursa olsun akış aynıdır:

  1. Kapsamı seçin. Bütün kataloğu değil, ciroyu taşıyan ve fiyata duyarlı ürünleri izleyin.
  2. Ürünleri eşleştirin. Her stok kodunuzun (SKU) karşısına rakipteki aynı ürünün adresini yazın.
  3. Sayfaları düzenli aralıklarla okuyun. Fiyat, para birimi, stok durumu ve varsa satıcı adı alınır.
  4. Her okumayı tarihiyle saklayın. Yalnızca son fiyatı tutan bir tablo "ne zaman değişti" sorusuna cevap veremez.
  5. Değişimi eşikle karşılaştırın ve haber verin. Her kuruşluk oynama için e-posta gelirse uyarılar üç gün sonra okunmaz olur.
  6. Kararı insana bırakın. Uyarı bir öneridir. Fiyatı kimin, hangi kuralla değiştireceği ayrı bir iş kararıdır.

Veri nereden gelir: satıcı API'si, hazır araç, kendi betiğiniz?

Önce resmi yola bakın. Pazaryerleri, satıcılarına kendi ürün, stok ve fiyat verilerini yönetebilecekleri API'ler sunar. Örneğin Trendyol'un entegrasyon belgeleri ürün aktarımı, stok ve fiyat yönetimi ile sipariş servislerini kapsar. Bu API'ler kendi mağazanızın verisi içindir; rakip tarafında verdikleri sınırlıdır. Trendyol'un Buybox kontrol servisi yalnızca sizin de sattığınız barkodlar için buybox fiyatını, sıranızı ve ürünün başka satıcısı olup olmadığını döndürür. Rakibin kendi sitesindeki fiyatı, stoku ya da sizin listelemediğiniz ürünleri buradan göremezsiniz. Yine de karşılaştırmanın sol sütunu, yani sizin güncel fiyatınız, elle tutulan bir tablodan değil buradan okunmalıdır.

Rakip tarafı için seçenekler yan yana şöyle durur:

YöntemNe verirEmekNe zaman uygun
Satıcı API'siKendi fiyat, stok ve sipariş veriniz; bazı pazaryerlerinde sattığınız ürünün buybox fiyatıBir kez entegrasyonHer durumda, karşılaştırmanın kendi tarafı için
Elle kontrol ve tabloAz sayıda ürünün anlık fiyatıHer gün tekrar eden insan emeği20-30 ürün, haftalık bakış
Hazır fiyat takip aracıEşleştirme, tarama ve rapor ekranıAylık abonelik, kurulum azYazılım ekibi yoksa, standart pazaryerleri yetiyorsa
Kendi betiğinizİstediğiniz site, alan ve sıklıkGeliştirme ve bakımÖzel siteler, kendi veri ambarınıza akış, esnek uyarı kuralları
Otomasyon aracıyla akışBetiğin kodsuz haliOrtaKüçük liste, hazır tablo ve bildirim bağlantıları

Son satırın bir örneğini n8n ile Web Scraping yazımızda kurduk. Hiç kod yazmadan bir sayfadan tablo almanın yollarını ise Web Sitesinden Veri Çekme yazımızda basamak basamak anlattık.

Ürün eşleştirme nasıl yapılır?

Yanlış eşleşen bir ürün, hiç izlenmeyen üründen daha zararlıdır: 64 GB modelin fiyatını 128 GB modelle kıyaslayan bir uyarı sizi gereksiz bir indirime götürür. Eşleştirmede güvenilirlik sırası şöyledir:

  • Barkod (GTIN/EAN). İki sayfada aynı barkod varsa ürün aynıdır. Yapılandırılmış veride gtin13 ya da gtin alanında, bazen ürün özellikleri tablosunda bulunur.
  • Üretici parça numarası (MPN) ve marka. Elektronik ve yedek parçada barkoddan daha sık görünür.
  • Başlık ve özellik karşılaştırması. Barkod yoksa marka, model, kapasite, renk ve adet ayrı ayrı karşılaştırılır.

Varyantlı ürünlerde (beden, renk, kapasite) her varyant ayrı bir satırdır ve çoğu sitede ayrı bir adresi ya da adres parametresi vardır. Paketli satışlarda (3'lü, 6'lı) fiyatı birim fiyata çevirmeden kıyaslamayın. Pazaryerlerinde aynı ürün sayfasında birden çok satıcı olabilir; "rakip" sayfa değil, o sayfadaki belirli bir satıcıdır.

Eşleştirme tablosunda sku, rakip, url, eşleşme türü ve son kontrol tarihi sütunları yeter. Elle eşleştirilen satırları aralıklarla yeniden gözden geçirin: rakip ürünü kaldırıp aynı adrese yeni modeli koyabilir.

Hangi fiyatı kaydetmelisiniz?

Bir ürün sayfasında tek bir fiyat yoktur. Neyi kaydettiğinizi baştan belirlemezseniz geçmiş tablonuz elmayla armudu yan yana dizer.

  • Liste fiyatı ve indirimli fiyat. İkisini ayrı sütunlarda tutun. Müşterinin ödediği indirimli olandır.
  • Sepette ya da kuponla düşen fiyat. Ürün sayfasında görünmeyebilir. Herkese açık sayfada yazmıyorsa takip kapsamının dışında bırakın; giriş yapmış hesapla otomatik gezinme bu yazının konusu değil.
  • Kargo. Ücretsiz kargo eşiği, düşük fiyatlı ürünlerde gerçek farkı belirler.
  • Para birimi. Yurt dışı rakiplerde para birimini fiyatla birlikte kaydedin, çevirmeyi rapor aşamasına bırakın.
  • Stok durumu. Stokta olmayan rakibin fiyatı sizi bağlamaz.

Tarama sıklığı nasıl belirlenir?

Sıklığı merak değil, iki soru belirler: fiyat bu kategoride ne kadar hızlı değişiyor ve siz ne kadar hızlı tepki verebiliyorsunuz? Fiyatları haftada bir güncelleyen bir ekip için saatlik tarama rakibin sunucusuna yük, size de okunmayan veri üretir.

Ürün sınıfıMakul başlangıçGerekçe
Kampanya dönemindeki çok satanlarGünde birkaç kezFiyat gün içinde değişebilir, tepki süresi kısadır
Düzenli satan ana ürünlerGünde birÇoğu fiyat kararı günlük verilir
Uzun kuyruk, yavaş dönen ürünlerHaftada birDeğişim seyrek, tepki ihtiyacı düşük
Rakipte stokta olmayan ürünlerGünde bir, yalnız stok içinStok dönüşü fiyat kadar değerli bir bilgidir

İstek sayısını basit bir çarpımla hesaplayın: ürün sayısı × günlük tarama sayısı. 500 ürünü günde dört kez okumak 2.000 istek eder. İstekler arasında iki saniye beklerseniz bir tur yaklaşık 17 dakika sürer ve bu, tek bir site için sakin bir tempodur. Aynı hesap 50.000 ürün ve saatlik tarama için yapıldığında kuyruk, hız sınırı ve IP dağıtımı konuları devreye girer. Hız sınırına uymanın yollarını Web Scraping'de Engellenmeden Veri Toplama Yöntemleri, sunucunun "yavaşla" demesini ise 429 Too Many Requests yazımızda anlattık.

Fiyat sayfanın neresinde durur?

Geliştirici tarafına geçiyoruz. Fiyatı ekranda gördüğünüz yerden, yani bir CSS sınıfının içindeki metinden okumak en kırılgan yoldur: tasarım değişir, sınıf adı değişir, betik sessizce bozulur. Çoğu mağaza aynı bilgiyi arama motorları için sayfaya bir kez daha, yapılandırılmış biçimde koyar. Bu veri <script type="application/ld+json"> etiketinin içinde durur ve schema.org'un Offer türündeki price, priceCurrency ve availability alanlarını taşır. Google'ın satıcı listeleri için yapılandırılmış veri belgesi price ve priceCurrency alanlarını zorunlu tutar; aramada fiyatıyla görünmek isteyen mağaza bu veriyi güncel tutar.

Okuma sırası bu yüzden şöyle olmalı:

  1. Sayfada JSON-LD Product verisi varsa fiyatı oradan alın.
  2. Yoksa sayfanın kendi HTML yapısına göre bir seçici yazın.
  3. Fiyat HTML'de hiç yoksa sayfa veriyi JavaScript ile yüklüyordur. Bu durumu ve gömülü JSON'u okumanın diğer biçimlerini Statik ve Dinamik Sayfalar yazımızda anlattık; seçici yazımı için CSS Selector ve XPath yazımıza bakın.

Python ile çalışan örnek: fiyat geçmişi ve eşik uyarısı

Örneği gerçek bir mağazada değil, books.toscrape.com üzerinde çalıştırıyoruz. Site, scraping alıştırması için yayınlanan kurgusal bir kitapçıdır ve ana sayfasındaki uyarıya göre fiyatları rastgele atanmıştır. Sayfalarında JSON-LD yok. Gerçek mağazalarda iki durumla da karşılaşırsınız; betik bu yüzden önce JSON-LD'yi dener, bulamayınca sitenin ürün bilgisi tablosuna düşer.

Gerekenler: Python 3 ve iki paket (pip install requests beautifulsoup4). SQLite, Python'un standart kütüphanesindeki sqlite3 modülüyle gelir; ayrı bir veritabanı sunucusu kurmazsınız.

python
import json
import re
import sqlite3
import time
from datetime import datetime, timezone
from decimal import Decimal

import requests
from bs4 import BeautifulSoup

DB = "fiyatlar.db"
ESIK_YUZDE = Decimal("5")   # bu orandan büyük değişim uyarı üretir
BEKLEME = 2.0               # aynı siteye iki istek arasındaki süre (saniye)
PROXY = None                # örnek: "http://user:pass@pr.proxynet.io:8000"
USER_AGENT = "OrnekFiyatBotu/1.0 (+https://ornek.com/bot-hakkinda)"

# Kendi stok kodunuz -> rakipteki aynı ürünün sayfası
URUNLER = {
    "KTP-001": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
    "KTP-002": "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
    "KTP-003": "https://books.toscrape.com/catalogue/soumission_998/index.html",
}

PARA_BIRIMI = {"£": "GBP", "€": "EUR", "$": "USD", "₺": "TRY", "TL": "TRY"}


def fiyat_ayristir(metin):
    """'£51.77' ya da '1.299,90 TL' gibi bir metni Decimal'e çevirir."""
    sayi = re.sub(r"[^\d.,]", "", metin)
    if re.fullmatch(r"\d{1,3}(\.\d{3})+", sayi):
        sayi = sayi.replace(".", "")                     # 1.299 -> 1299 (kuruşsuz yazım)
    elif sayi.rfind(",") > sayi.rfind("."):
        sayi = sayi.replace(".", "").replace(",", ".")   # 1.299,90 -> 1299.90
    else:
        sayi = sayi.replace(",", "")                     # 1,299.90 -> 1299.90
    return Decimal(sayi)


def jsonld_oku(soup):
    """Sayfada schema.org Product verisi varsa fiyatı oradan okur."""
    for etiket in soup.find_all("script", type="application/ld+json"):
        try:
            veri = json.loads(etiket.string or "")
        except json.JSONDecodeError:
            continue
        adaylar = veri if isinstance(veri, list) else veri.get("@graph", [veri])
        for aday in adaylar:
            tur = aday.get("@type")
            if "Product" not in (tur if isinstance(tur, list) else [tur]):
                continue
            teklif = aday.get("offers") or {}
            if isinstance(teklif, list):
                teklif = teklif[0]
            fiyat = teklif.get("price") or teklif.get("lowPrice")
            if fiyat is None:
                continue
            return {
                "fiyat": Decimal(str(fiyat)),
                "para_birimi": teklif.get("priceCurrency"),
                "stokta": str(teklif.get("availability", "")).endswith("InStock"),
                "kaynak": "json-ld",
            }
    return None


def html_oku(soup):
    """JSON-LD yoksa sayfanın kendi yapısı: books.toscrape.com ürün tablosu."""
    tablo = {
        satir.th.get_text(strip=True): satir.td.get_text(strip=True)
        for satir in soup.select("table.table-striped tr")
    }
    ham = tablo.get("Price (incl. tax)") or soup.select_one("p.price_color").get_text()
    simge = next((s for s in PARA_BIRIMI if s in ham), None)
    return {
        "fiyat": fiyat_ayristir(ham),
        "para_birimi": PARA_BIRIMI.get(simge),
        "stokta": tablo.get("Availability", "").startswith("In stock"),
        "kaynak": "html",
    }


def urun_cek(session, url):
    yanit = session.get(url, timeout=20)
    yanit.raise_for_status()
    yanit.encoding = "utf-8"   # sunucu charset bildirmiyor; £ simgesi bozulmasın
    soup = BeautifulSoup(yanit.text, "html.parser")
    if soup.select_one("h1") is None:
        raise ValueError("200 döndü ama ürün sayfası değil")
    return jsonld_oku(soup) or html_oku(soup)


def veritabani():
    db = sqlite3.connect(DB)
    db.execute(
        """CREATE TABLE IF NOT EXISTS fiyatlar (
               sku TEXT NOT NULL,
               url TEXT NOT NULL,
               fiyat_kurus INTEGER NOT NULL,
               para_birimi TEXT,
               stokta INTEGER NOT NULL,
               kaynak TEXT,
               tarih TEXT NOT NULL
           )"""
    )
    db.execute("CREATE INDEX IF NOT EXISTS idx_sku_tarih ON fiyatlar (sku, tarih)")
    return db


def onceki_kayit(db, sku):
    return db.execute(
        "SELECT fiyat_kurus, stokta FROM fiyatlar WHERE sku = ? ORDER BY tarih DESC LIMIT 1",
        (sku,),
    ).fetchone()


def uyar(mesaj):
    print("UYARI:", mesaj)   # e-posta ya da sohbet webhook'u buraya bağlanır


def main():
    db = veritabani()
    session = requests.Session()
    session.headers["User-Agent"] = USER_AGENT
    if PROXY:
        session.proxies = {"http": PROXY, "https": PROXY}

    for sku, url in URUNLER.items():
        try:
            urun = urun_cek(session, url)
        except (requests.RequestException, ValueError, AttributeError) as hata:
            print(f"{sku}: okunamadı ({hata})")
            time.sleep(BEKLEME)
            continue

        kurus = int(urun["fiyat"] * 100)
        onceki = onceki_kayit(db, sku)
        if onceki:
            eski_kurus, eski_stok = onceki
            degisim = Decimal(kurus - eski_kurus) * 100 / Decimal(eski_kurus)
            if abs(degisim) >= ESIK_YUZDE:
                uyar(f"{sku}: {eski_kurus / 100:.2f} -> {kurus / 100:.2f} "
                     f"{urun['para_birimi']} (%{degisim:+.1f})")
            if bool(eski_stok) != urun["stokta"]:
                uyar(f"{sku}: stok durumu değişti, şimdi {'var' if urun['stokta'] else 'yok'}")

        db.execute(
            "INSERT INTO fiyatlar VALUES (?, ?, ?, ?, ?, ?, ?)",
            (sku, url, kurus, urun["para_birimi"], int(urun["stokta"]), urun["kaynak"],
             datetime.now(timezone.utc).isoformat(timespec="seconds")),
        )
        db.commit()
        print(f"{sku}: {urun['fiyat']} {urun['para_birimi']} "
              f"stok={'var' if urun['stokta'] else 'yok'} ({urun['kaynak']})")
        time.sleep(BEKLEME)

    db.close()


if __name__ == "__main__":
    main()

İlk çalıştırmada üç satır yazılır ve karşılaştırılacak eski kayıt olmadığı için uyarı çıkmaz:

text
KTP-001: 51.77 GBP stok=var (html)
KTP-002: 53.74 GBP stok=var (html)
KTP-003: 50.10 GBP stok=var (html)

Alıştırma sitesinin fiyatları değişmediği için, uyarıyı görmek üzere veritabanındaki son kaydı elle değiştirdik: KTP-001 fiyatını 45,00 yaptık, KTP-002 için stoku "yok" diye işaretledik. İkinci çalıştırmanın çıktısı:

text
UYARI: KTP-001: 45.00 -> 51.77 GBP (%+15.0)
KTP-001: 51.77 GBP stok=var (html)
UYARI: KTP-002: stok durumu değişti, şimdi var
KTP-002: 53.74 GBP stok=var (html)
KTP-003: 50.10 GBP stok=var (html)

Koddaki dört tercih bilinçlidir:

  • Fiyat kuruş cinsinden tam sayı olarak saklanır. Ondalıklı sayılar (float) para hesabında yuvarlama hatası biriktirir. Decimal ile ayrıştırıp kuruşa çevirmek yüzde hesabını kesin tutar.
  • Her okuma yeni bir satırdır. Fiyat değişmese bile satır yazılır; böylece "o gün baktık ve aynıydı" ile "o gün bakamadık" birbirinden ayrılır.
  • Okunamayan ürün atlanır, tur durmaz. Hata ekrana yazılır ve sıradaki ürüne geçilir. Hangi durum kodunda yeniden denenip hangisinde durulacağını Scraping'de HTTP Hata Kodları yazımızdaki yeniden deneme koduyla birleştirebilirsiniz.
  • User-Agent botun kim olduğunu söyler. Değerin nasıl seçileceği User-Agent Nedir? yazımızda.

PROXY satırını doldurduğumuzda aynı betiği kimlik doğrulamalı bir yerel test proxy'si üzerinden de çalıştırdık. Sonuç değişmedi; yanlış parolada ise her ürün için ProxyError (407) düştü ve tur yine tamamlandı.

Ürün listesi nasıl çıkarılır: kategori sayfaları ve sayfalama

Rakibin bir kategorisindeki bütün ürün adreslerini toplamak için kategori sayfalarını gezmeniz gerekir ve liste neredeyse her zaman sayfalara bölünmüştür. En sağlam yöntem sayfa numarası uydurmak değil, sayfadaki "sonraki" bağlantısını izlemektir:

python
import time
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup


def urun_adresleri(session, baslangic, en_fazla_sayfa=3, bekleme=2.0):
    """Kategori sayfalarını 'sonraki' bağlantısını izleyerek gezer, ürün adreslerini toplar."""
    adres, sonuc = baslangic, []
    for _ in range(en_fazla_sayfa):
        yanit = session.get(adres, timeout=20)
        yanit.raise_for_status()
        soup = BeautifulSoup(yanit.text, "html.parser")
        sonuc += [urljoin(adres, a["href"]) for a in soup.select("article.product_pod h3 a")]
        sonraki = soup.select_one("li.next a")
        if sonraki is None:
            break
        adres = urljoin(adres, sonraki["href"])
        time.sleep(bekleme)
    return sonuc


session = requests.Session()
session.headers["User-Agent"] = "OrnekFiyatBotu/1.0 (+https://ornek.com/bot-hakkinda)"
adresler = urun_adresleri(session, "https://books.toscrape.com/catalogue/category/books/mystery_3/index.html")
print(len(adresler), "ürün bulundu")

Alıştırma sitesinin "Mystery" kategorisinde bu fonksiyon iki sayfa gezip 32 ürün adresi döndürdü. Sayfa üst sınırı (en_fazla_sayfa), hatalı bir "sonraki" bağlantısının betiği sonsuz döngüye sokmasını önler. Sonsuz kaydırma, "daha fazla yükle" düğmesi, imleç tabanlı API'ler ve yarıda kalan taramayı kaldığı yerden sürdüren URL kuyruğu gibi konuları Sayfalama (Pagination) Nedir, Scraping'de Nasıl Taranır? yazımızda ele aldık. Aynı işi hazır bir çatıyla kurmak isterseniz Scrapy Nedir ve Proxy ile Nasıl Kullanılır? yazımıza bakın.

Geçmiş nasıl sorgulanır ve betik nasıl zamanlanır?

Son 30 günün en düşük ve en yüksek fiyatı tek bir sorgudur:

sql
SELECT sku,
       MIN(fiyat_kurus) / 100.0 AS en_dusuk,
       MAX(fiyat_kurus) / 100.0 AS en_yuksek,
       COUNT(*)                 AS olcum
FROM fiyatlar
WHERE tarih >= date('now', '-30 days')
GROUP BY sku
ORDER BY sku;

Bu tablo, indirimin kaç gün sürdüğünü ve "indirim" diye duyurulan fiyatın geçen ayın normal fiyatı olup olmadığını gösterir.

Zamanlama için Linux'ta cron satırı (0 */6 * * * python3 /opt/fiyat/fiyat_takip.py, altı saatte bir), Windows'ta Görev Zamanlayıcı işi görür. Turlar için gece saatlerini tercih edin; rakibin sitesi de sizinki gibi gündüz müşteriye hizmet ediyor.

Türkiye'den bakmak neden fark eder?

Bir mağazanın gösterdiği fiyat ve stok, ziyaretçinin bulunduğu ülkeye göre değişebilir: para birimi, vergi, teslimat bölgesi, bölgeye özel kampanya. Betiğiniz yurt dışındaki bir bulut sunucusunda çalışıyorsa müşterinizin gördüğü sayfayı değil, o konuma gösterilen sayfayı kaydediyor olabilirsiniz.

Çözüm, isteği müşterinizle aynı ülkeden çıkarmaktır. Residential Proxy ile çıkış ülkesini seçebilir, Türkiye'deki müşterinin gördüğü sayfa için Türkiye konumlu IP adreslerini kullanabilirsiniz. IP konumunun nasıl belirlendiğini ve neden bazen yanlış çıktığını IP Adresinden Konum Bulunur mu? yazımızda anlattık. Proxy'nin bu işteki ikinci rolü, çok sayıda ürünü tarayan bir işte yükü birden çok adrese dağıtmaktır. Rotasyonun mantığı IP Rotasyonu Nedir ve Nasıl Çalışır? yazımızda. Rotating ile sticky arasındaki seçimi fiyat takibi sayfamızdaki sorular bölümü yanıtlıyor.

Proxy bir izin belgesi değildir. Sitenin hız sınırı ve robots.txt kuralları, isteğin hangi IP'den çıktığından bağımsız olarak geçerlidir.

Stok bildirimi aynı akışla kurulur mu?

Evet. Yukarıdaki betik stok durumunu zaten kaydediyor ve değiştiğinde uyarı veriyor. Rakibin stokunun bitmesi, o günlerde indirim yapmanıza gerek olmadığını söyler; yeniden stoka girmesi fiyatı gözden geçirme zamanıdır.

Çizgi şurada: bildirim almak ile otomatik satın almak aynı şey değildir. Sınırlı sayıdaki ürünü stoka girdiği anda botla toplayıp yeniden satmak diğer alıcıların zararınadır ve mağazaların çoğu bunu şartlarında yasaklar. Bu yazıdaki akış bilgi toplar, sepete dokunmaz. Satın alma adımını otomatikleştiren ajanların neden engellendiğini AI Alışveriş Ajanları Neden Sitelerde Engelleniyor? yazımızda ele aldık.

Sınırlar: site şartları, robots.txt ve rekabet hukuku

Rakibin vitrinindeki fiyata bakmak ticaretin kendisi kadar eskidir. Otomatik takibi meşru tutan şey yöntemdir:

  • Yalnızca herkese açık ürün sayfaları. Giriş gerektiren alanlar, müşteri yorumlarındaki kişisel veriler ve hesap otomasyonu kapsam dışıdır.
  • robots.txt ve site şartları. Taramadan önce ikisini de okuyun. Pazaryerlerinin kullanım koşulları otomatik erişimi sınırlayan maddeler içerebilir; böyle bir madde varsa resmi API'yi, veri ortaklığını ya da izin istemeyi değerlendirin. Dosyanın nasıl okunacağı robots.txt Dosyası Nedir, Nasıl Okunur? yazımızda, hukuki çerçeve Web Scraping Yasal mı? yazımızda.
  • Düşük hız ve önbellek. İstekler arasında bekleyin ve aynı sayfayı karar temponuzun gerektirdiğinden sık istemeyin.
  • Koruma ekranı çıktıysa durun. Doğrulama sayfası bir arıza değil, sitenin verdiği bir cevaptır. Bu sistemlerin nasıl çalıştığını Bot Tespiti Nasıl Yapılır? yazımızda anlattık.

Bir de rekabet hukuku var. Rakibin herkese açık fiyatını izleyip kendi fiyatınızı tek başınıza belirlemek olağan bir ticari davranıştır. Rakiplerle fiyat konusunda anlaşmak ya da fiyat bilgisini karşılıklı paylaşarak birlikte hareket etmek ise başka bir şeydir: 4054 sayılı Rekabetin Korunması Hakkında Kanun 4. maddesinde, rekabeti kısıtlayan anlaşmaları ve uyumlu eylemleri yasaklar ve ilk örnek olarak alım ya da satım fiyatının tespit edilmesini sayar. Otomatik fiyatlandırma kuralları kuruyorsanız bu sınırı bir hukukçuyla konuşun.

Kullanım alanları

  • Pazaryeri satıcıları: Aynı ürünü satan diğer satıcıların fiyatı ve stoku. Platforma özel altyapı notları Trendyol Proxy, Hepsiburada Proxy ve Amazon Proxy sayfalarımızda.
  • Kendi sitesinden satan markalar: Yetkili bayilerin tavsiye edilen fiyata uyup uymadığının izlenmesi. Genel kurgu e-ticaret çözümü sayfamızda.
  • Veri ekipleri: Fiyat geçmişini talep tahmini ve kampanya analizine girdi olarak kullanmak. Toplama tarafının ölçeklenmesi veri kazıma çözümü sayfamızda.

Sık yapılan hatalar

  • Yalnızca son fiyatı saklamak. Geçmiş olmadan indirimin ne zaman başladığını, kaç gün sürdüğünü ve tekrarlanıp tekrarlanmadığını göremezsiniz.
  • Eşleştirmeyi bir kez yapıp unutmak. Rakip ürünü yeniler, adres aynı kalır, siz eski modelle yeni modeli kıyaslarsınız.
  • 200 yanıtını fiyat sanmak. Doğrulama ekranı ya da "ürün bulunamadı" sayfası da 200 dönebilir. Betikteki h1 kontrolü gibi bir doğrulama şarttır; fiyat alanı boşsa satır yazmayın.
  • Virgül ve noktayı karıştırmak. 1.299,90 ile 1,299.90 aynı sayıdır. Ayrıştırma fonksiyonunu hedef sitenin gerçek örnekleriyle test edin.
  • Rakibin fiyatına otomatik ve sınırsız eşitlenmek. İki otomatik kural karşılıklı çalışırsa fiyat dibe iner. Alt sınırı maliyetinize göre siz koyun.

Karar rehberi

İhtiyaçÖneri
Kendi fiyat ve stokunuzu güncel tutmakPazaryerinin satıcı API'si
20-30 ürün, haftalık bakışElle kontrol ve tablo
Yüzlerce ürün, yazılım ekibi yokHazır fiyat takip aracı ya da otomasyon akışı
Özel siteler, kendi veri ambarı, esnek uyarıKendi Python betiğiniz ve SQLite
On binlerce ürün, saatlik taramaKuyruklu tarayıcı (Scrapy), sunucu veritabanı, IP dağıtımı
Fiyat ülkeye göre değişiyorMüşterinizin ülkesinden çıkan IP
Site doğrulama ekranı gösteriyorDurun; hızı, şartları ve resmi API seçeneğini gözden geçirin

Sık sorulan sorular

Rakip fiyat takibi yasal mı?

Herkese açık bir ürün sayfasındaki fiyata bakmak ve bunu not etmek olağan bir ticari faaliyettir. Sorun yöntemde çıkar: giriş arkasındaki veriye erişmek, site şartlarını ya da robots.txt'yi yok saymak, sunucuyu yoracak hızda taramak. Ayrıca topladığınız bilgiyi rakiplerle fiyat anlaşması için kullanmak rekabet hukukuna aykırıdır.

Fiyat takibi Excel ile yapılabilir mi?

Az sayıda ürün için evet. Elle girilen bir tablo ya da Excel'in web'den veri alma özelliği başlangıç için yeterlidir. Sınırı geçmişte ve uyarıda ortaya çıkar: tablo son durumu gösterir, değişimi haber vermez. Ürün sayısı birkaç düzineyi geçince SQLite gibi küçük bir veritabanı daha az zahmetlidir.

Trendyol ya da Hepsiburada API'si rakip fiyatlarını verir mi?

Kısmen. Satıcı API'leri önce kendi mağazanızın ürün, stok, fiyat ve sipariş verisini yönetmeniz içindir. Trendyol'un Buybox kontrol servisi, sizin de sattığınız barkodlarda buybox fiyatını ve sıranızı verir; rakibin fiyat geçmişi, stoku ya da başka sitelerdeki fiyatı için bir uç nokta yoktur. Hangi pazaryerinin ne sunduğunu güncel entegrasyon belgesinden kontrol edin. Bu API'lerin asıl işi kendi güncel fiyatınızı okumak ve fiyat kararını mağazanıza geri yazmaktır.

Günde kaç kez tarama yapmalıyım?

Fiyat kararını ne sıklıkla veriyorsanız o kadar. Çoğu katalog için günde bir tarama yeter; kampanya dönemindeki çok satanlarda günde birkaç tura çıkılır, yavaş dönen ürünler haftalığa indirilir.

Fiyat takibi için proxy şart mı?

Küçük bir liste ve düşük sıklık için değil. İki durumda gerekir: fiyat ülkeye göre değişiyorsa ve betiğiniz müşterinizden farklı bir ülkede çalışıyorsa, ya da ürün sayısı isteklerin tek adresten çıkmasını sorunlu kılacak kadar büyükse. Hangi IP türünün hangi işe uyduğunu fiyat takibi çözümü sayfamızda karşılaştırdık.

Sayfada JSON-LD yoksa fiyatı nereden okurum?

Önce sayfa kaynağında fiyatın düz HTML içinde olup olmadığına bakın; varsa örnekteki gibi bir seçici yazın ve mümkünse sınıf adı yerine ürün bilgisi tablosu gibi daha kalıcı bir yapıya tutunun. Fiyat kaynakta hiç yoksa sayfa veriyi sonradan yüklüyordur. O durumda tarayıcının ağ sekmesinden verinin geldiği isteği bulmak, headless tarayıcı çalıştırmaktan daha hafif bir çözümdür.

Özetle

Rakip fiyat takibi bir yazılım değil, bir akıştır: doğru eşleştirilmiş bir ürün listesi, kararlarınızın temposuna uygun bir tarama sıklığı, tarih damgalı bir geçmiş tablosu ve az ama anlamlı uyarılar. Kendi tarafınızın verisini satıcı API'sinden alın, rakip tarafında herkese açık sayfalarla, robots.txt'yle ve düşük hızla sınırlı kalın. Yüz elli satırlık bir Python betiği ve tek dosyalık bir SQLite veritabanı, çoğu katalog için bu işi görür. Ölçek büyüdüğünde ve fiyatı müşterinizin ülkesinden görmeniz gerektiğinde altyapı seçeneklerini fiyat takibi çözümü sayfamızda bulabilirsiniz.

ChatGPT'ye sorClaude'a sor