Use Cases

CAPTCHA İşleme ile E-Ticaret Fiyat Takibi

Bir fiyat takibi hattı kurarsınız, birkaç gün sorunsuz çalışır, sonra bir sabah tablolarınızda boşluklar belirir. Sebep genellikle tektir: hedef sayfa bir CAPTCHA döndürmüş, botunuz da sessizce boş satır kaydetmiştir. Doğru yaklaşım, CAPTCHA'yı beklenmedik bir hata değil, iş akışının olağan bir adımı olarak ele almaktır. CaptchaAI; reCAPTCHA v2 ve v3, Cloudflare Turnstile ve Cloudflare doğrulama akışı gibi türleri API üzerinden çözer, böylece fiyat botunuz sayfa doğrulama istese bile durmadan veri toplamaya devam eder.

Fiyat takibi neden CAPTCHA'ya takılır?

Büyük e-ticaret platformları, ürün sayfalarını otomatik trafiğe karşı korur. Kısa aralıklarla çok sayfa çeken bir izleme botu, bir insan ziyaretçiden farklı davranır ve tespit sistemlerini tetikler. En sık görülen tetikleyiciler şunlardır:

  • Aynı IP'den kısa sürede gelen yoğun istek
  • Tekdüze, saniye hassasiyetinde tekrar eden zamanlama
  • Eksik veya tutarsız tarayıcı başlıkları
  • Aynı oturumdan olağandışı sayıda sayfa gezintisi

Bu sinyallerden biri eşiği aştığında sunucu, ürün fiyatı yerine bir CAPTCHA doğrulaması döndürür.

Platform CAPTCHA türü Tetikleyici
Amazon Resim CAPTCHA, reCAPTCHA Yüksek istek hacmi
Walmart Cloudflare Turnstile Bot tespiti
eBay reCAPTCHA v2 Şüpheli erişim desenleri
Best Buy Cloudflare doğrulama akışı Tüm otomatik trafik
Shopify mağazaları reCAPTCHA v3 Mağaza yapılandırmasına göre değişir

CAPTCHA yönetimi olmadan hat sessizce başarısız olur: istek başarılı görünür ama gövde ürün yerine doğrulama sayfasıdır, ayrıştırıcı da null fiyat üretir. Bu boşluklar veri setinizde fark edilmeden birikir ve fiyatlandırma kararlarınızı yanıltır.

E-ticaret fiyat takibi mimarisi

Güvenilir bir hattın omurgası birkaç adımdan oluşur:

  1. Zamanlayıcı, izlenecek URL'leri kuyruğa alır.
  2. Worker'lar sayfaları eşzamanlı çeker.
  3. Yanıtta CAPTCHA varsa sitekey çıkarılıp CaptchaAI'ye gönderilir.
  4. Dönen token ile sayfa yeniden istenir ve fiyat ayrıştırılır.
  5. Sonuç veritabanına yazılır, fiyat değişiminde uyarı tetiklenir.

CAPTCHA kontrolünü çekme ile ayrıştırma arasına yerleştirmek, doğrulama sayfalarının veri hattına sızmasını ve boş fiyat üretmesini engeller.

Scheduler (every 30 min)
    → URL Queue
        → Scraper Workers (5-10 concurrent)
            → Fetch page
            → CAPTCHA detected?
                → Yes → CaptchaAI → Solve → Retry page
                → No → Parse prices
            → Store in database
        → Alert on price changes

Worker'ları eşzamanlı çalıştırmak verimi artırır; CaptchaAI planınızdaki thread sayısı da kaç CAPTCHA'yı aynı anda çözebileceğinizi belirler. İkisini birbirine yakın ölçeklemek, kuyruğun tıkanmasını önler.

Uygulama: fiyat monitörünü kodlama

Akış her dilde aynıdır: sayfayı çekin, HTML içinde bir sitekey arayın, bulursanız türe uygun method ile CaptchaAI'ye görev gönderin, sonucu sorgulayın ve dönen token'ı doğru alanla (g-recaptcha-response ya da cf-turnstile-response) geri gönderin. Ardından sayfayı yeniden çekip fiyatı ayrıştırırsınız.

Python ile fiyat monitörü

Aşağıdaki örnek görevi in.php uç noktasına gönderir, sonucu res.php üzerinden periyodik sorgulama ile bekler ve hem reCAPTCHA hem Turnstile'ı tek akışta ele alır:

import requests
import time
import re
import json
import os
from datetime import datetime

API_KEY = os.environ["CAPTCHAAI_API_KEY"]
BASE_URL = "https://ocr.captchaai.com"


def solve_captcha(method, params):
    params["key"] = API_KEY
    params["method"] = method

    resp = requests.get(f"{BASE_URL}/in.php", params=params)
    if not resp.text.startswith("OK|"):
        raise Exception(f"Submit failed: {resp.text}")

    task_id = resp.text.split("|")[1]

    for _ in range(60):
        time.sleep(5)
        result = requests.get(f"{BASE_URL}/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id,
        })
        if result.text == "CAPCHA_NOT_READY":
            continue
        if result.text.startswith("OK|"):
            return result.text.split("|", 1)[1]
        raise Exception(f"Solve failed: {result.text}")

    raise TimeoutError("CAPTCHA solve timed out")


def fetch_with_captcha(url, session):
    """Fetch a page, solving CAPTCHAs if encountered."""
    resp = session.get(url)

    # Check for reCAPTCHA
    match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', resp.text)
    if match:
        site_key = match.group(1)
        token = solve_captcha("userrecaptcha", {
            "googlekey": site_key,
            "pageurl": url,
        })
        resp = session.post(url, data={"g-recaptcha-response": token})

    # Check for Turnstile
    match = re.search(
        r'class="cf-turnstile"[^>]*data-sitekey=["\']([^"\']+)', resp.text
    )
    if match:
        site_key = match.group(1)
        token = solve_captcha("turnstile", {
            "sitekey": site_key,
            "pageurl": url,
        })
        resp = session.post(url, data={"cf-turnstile-response": token})

    return resp


def extract_price(html, selectors):
    """Extract price from HTML using regex patterns."""
    for pattern in selectors:
        match = re.search(pattern, html)
        if match:
            price_str = match.group(1).replace(",", "")
            return float(price_str)
    return None


def monitor_prices(products):
    """Monitor prices for a list of products."""
    session = requests.Session()
    session.headers["User-Agent"] = (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 Chrome/120.0.0.0"
    )

    results = []
    for product in products:
        try:
            resp = fetch_with_captcha(product["url"], session)
            price = extract_price(resp.text, product["selectors"])

            results.append({
                "name": product["name"],
                "url": product["url"],
                "price": price,
                "timestamp": datetime.utcnow().isoformat(),
                "status": "ok",
            })
            print(f"  {product['name']}: ${price}")

        except Exception as e:
            results.append({
                "name": product["name"],
                "url": product["url"],
                "price": None,
                "timestamp": datetime.utcnow().isoformat(),
                "status": f"error: {e}",
            })
            print(f"  {product['name']}: ERROR - {e}")

    return results


# Define products to monitor
products = [
    {
        "name": "Wireless Headphones",
        "url": "https://example.com/product/headphones",
        "selectors": [
            r'class="price"[^>]*>\$?([\d,]+\.?\d*)',
            r'itemprop="price" content="([\d.]+)"',
        ],
    },
    {
        "name": "Bluetooth Speaker",
        "url": "https://example.com/product/speaker",
        "selectors": [
            r'class="price"[^>]*>\$?([\d,]+\.?\d*)',
        ],
    },
]

print("Starting price check...")
results = monitor_prices(products)

# Save results
with open("prices.json", "w") as f:
    json.dump(results, f, indent=2)

extract_price içinde birden çok seçici tanımlamak, sitelerin farklı HTML işaretlemesine karşı dayanıklılık sağlar: biri tutmazsa sıradaki denenir.

Node.js ile fiyat monitörü

Node.js tarafında axios ile istek atar, cheerio ile HTML'i ayrıştırırsınız. Mantık Python ile aynıdır; yalnızca kütüphane API'leri değişir:

const axios = require("axios");
const cheerio = require("cheerio");

const API_KEY = process.env.CAPTCHAAI_API_KEY;

async function solveCaptcha(method, params) {
  params.key = API_KEY;
  params.method = method;

  const submit = await axios.get("https://ocr.captchaai.com/in.php", {
    params,
  });
  const taskId = String(submit.data).split("|")[1];

  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const poll = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "get", id: taskId },
    });
    const text = String(poll.data);
    if (text === "CAPCHA_NOT_READY") continue;
    if (text.startsWith("OK|")) return text.split("|").slice(1).join("|");
    throw new Error(text);
  }
  throw new Error("Timeout");
}

async function monitorPrice(url) {
  const resp = await axios.get(url);
  const $ = cheerio.load(resp.data);

  // Check for reCAPTCHA
  const siteKey = $(".g-recaptcha").attr("data-sitekey");
  if (siteKey) {
    const token = await solveCaptcha("userrecaptcha", {
      googlekey: siteKey,
      pageurl: url,
    });
    // Re-fetch with token
    const formResp = await axios.post(url, { "g-recaptcha-response": token });
    return cheerio.load(formResp.data);
  }

  const price = $('[itemprop="price"]').attr("content") || $(".price").text();
  return parseFloat(price.replace(/[^0-9.]/g, ""));
}

Zamanlamayı otomatikleştirme

İzleme, ancak düzenli çalıştığında değerlidir. En yalın çözüm cron'dur; sunucu düzeyinde çalışır ve süreç başına bir günlük dosyasına yazar:

# crontab -e
*/30 * * * * cd /opt/monitor && python price_monitor.py >> /var/log/prices.log 2>&1

Zamanlamayı uygulama içinde tutmayı tercih ederseniz Python'un schedule kütüphanesi aynı işi görür ve dağıtımı kolaylaştırır:

import schedule

schedule.every(30).minutes.do(lambda: monitor_prices(products))

while True:
    schedule.run_pending()
    time.sleep(60)

30 dakikalık aralık çoğu fiyat takibi için yeterlidir; kampanya dönemlerinde daha sık, gece saatlerinde daha seyrek çalıştırarak hem maliyeti hem tespit riskini azaltabilirsiniz.

Maliyet nasıl hesaplanır ve hangi plan yeterli?

CaptchaAI, çözüm başına değil eşzamanlı thread başına ücret alır ve her planda thread başına sınırsız çözüm sunar. Yani maliyetiniz, günlük çözüm sayısıyla değil, aynı anda kaç CAPTCHA çözdüğünüzle belirlenir. Küçük bir izleme listesi için BASIC ($15/ay, 5 thread) genellikle yeterlidir; günde on binlerce sayfa tarayan bir hat için STANDARD ($30/ay, 15 thread) veya ADVANCE ($90/ay, 50 thread) daha uygun olur.

Aşağıdaki değerler tahminidir; gerçek maliyet ortama, siteye ve hacme göre değişir.

Hacim CAPTCHA/gün Tahmini günlük maliyet
Her 30 dakikada bir 50 ürün ~2.400 ~$2–5
Her 15 dakikada bir 200 ürün ~19.200 ~$15–30
1000 ürün, saatlik ~24.000 ~$20–40

Her sayfa yüklemesi CAPTCHA tetiklemez; pratikte gerçek maliyet bu tahminlerden %50–70 daha düşük olabilir. Türkiye'deki geliştiriciler için bir ek avantaj da fiyatların USD ve öngörülebilir olmasıdır: TL kuru dalgalansa bile aylık thread maliyetiniz sabit kalır, bu da bütçelemeyi kolaylaştırır.

KVKK ve yetkili veri toplama

Fiyat verisi genellikle herkese açık olsa da, kazıma iş akışlarınızı yasal çerçevede tutmak önemlidir. Pratik birkaç kural:

  • Toplanan veriye kişisel bilgi (ör. satıcı adı, kullanıcı yorumu) karışıyorsa bu, KVKK (Kişisel Verilerin Korunması Kanunu) kapsamına girer.
  • CaptchaAI'yi yalnızca yetkiniz olan, herkese açık ürün sayfalarında kullanın; oturum arkası veriye erişmek için değil.
  • Kendi QA ve veri toplama süreçlerinizle sınırlı kalın.

Bu yaklaşım hem uyumluluğu korur hem de hattınızı uzun vadede sürdürülebilir kılar.

Sık sorulan sorular

Fiyat takibi için hangi CaptchaAI planı yeterli?

İhtiyaç, eşzamanlı istek sayınıza bağlıdır. Birkaç yüz ürünü aralıklı izliyorsanız BASIC ($15/ay, 5 thread) başlangıç için yeter; worker sayısını artırdıkça STANDARD ($30/ay, 15 thread) veya ADVANCE ($90/ay, 50 thread) planlarına geçin. Çözüm sayısında sınır olmadığı için yalnızca thread'i ölçeklersiniz.

CAPTCHA çözümü fiyat botumu yavaşlatır mı?

CAPTCHA yalnızca tetiklendiğinde araya girer; çoğu istek doğrulama görmeden geçer. Bir çözüm gerektiğinde birkaç saniyelik ek gecikme oluşur, ancak worker'ları eşzamanlı çalıştırdığınızda bu gecikme genel verime yayılır ve hattınızı durdurmaz.

reCAPTCHA v3'ü de aynı hatta çözebilir miyim?

Evet. CaptchaAI reCAPTCHA v2 ve v3, Cloudflare Turnstile ve Cloudflare doğrulama akışını destekler. Örnekteki fetch_with_captcha mantığını, sayfada hangi tür varsa uygun method ile görev gönderecek biçimde genişletmeniz yeterlidir.

Farklı para birimlerindeki fiyatları izleyebilir miyim?

Evet. Fiyatın yanındaki para birimi sembolünü de ayrıştırıp kaydedin. CaptchaAI, hedef sitenin diline veya bölgesine bakılmaksızın CAPTCHA türünü çözer; para birimi dönüşümünü ise kendi ayrıştırma katmanınızda yaparsınız.

CAPTCHA'yı çözsem bile veri boşlukları oluşur mu?

Nadiren; ağ hataları veya değişen HTML işaretlemesi satırların boş kalmasına yol açabilir. Başarısız istekleri üstel geri çekilme (exponential backoff) ile yeniden deneyin, istekleri zamana yayın ve tek seferde toplu çekim yapmayın. Bu, hem boşlukları hem de tespit riskini azaltır.

İlgili rehberler

Bu makale için yorumlar devre dışı bırakılmıştır.