Açık artırma listelerinde teklifleri ve fiyat hareketlerini otomatik izlerken karşınıza çıkan asıl engel reCAPTCHA v2'dir: arama, ilan ayrıntısı ve teklif geçmişi sayfaları belirli bir istek hızının üzerine çıktığınızda doğrulama ister. Çözüm nettir — doğrulamayı CaptchaAI API'si ile çözer, aynı oturumda isteğe devam eder ve izleme akışınızı kesintiye uğratmazsınız. Aşağıda, koleksiyon ürünlerinden ikinci el elektroniğe kadar tipik bir fiyat takibi senaryosunu reCAPTCHA v2 çözümüyle uçtan uca kuran Python ve JavaScript örneklerini bulacaksınız.
Açık artırma sitelerinde CAPTCHA nerede tetiklenir?
Açık artırma platformları, listeleme verisini ve arama işlevini reCAPTCHA v2 ile korur. Doğrulama en sık şu noktalarda devreye girer:
| Eylem | CAPTCHA türü | Tetikleyici desen |
|---|---|---|
| Arama ve listeleme gezintisi | reCAPTCHA v2 | Hızlı, ardışık aramalar |
| İlan ayrıntısını görüntüleme | reCAPTCHA v2 | Aynı IP'den yüksek hacim |
| Teklif geçmişini sorgulama | reCAPTCHA v2 | Tekrarlı ayrıntı sayfası yüklemeleri |
| Kategori gezinme | Cloudflare Turnstile | Bot benzeri gezinme hızı |
| Fiyat uyarısı sayfaları | reCAPTCHA v2 | Sık sayfa yenilemeleri |
reCAPTCHA v2 çözümüyle açık artırma izleme (Python)
Aşağıdaki AuctionMonitor sınıfı arama ve ilan isteklerini gönderir; bir CAPTCHA gördüğünde sitekey'i çıkarır, CaptchaAI ile çözer ve token'ı g-recaptcha-response alanıyla yeniden gönderir. requests.Session() sayesinde oturum kalıcılığı korunur, böylece her istekte yeniden doğrulama gerekmez.
import requests
import time
import re
from datetime import datetime
class AuctionMonitor:
def __init__(self, api_key):
self.api_key = api_key
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
def search_listings(self, auction_url, query, category=None):
"""Search auction listings, solving CAPTCHAs when triggered."""
params = {"q": query}
if category:
params["category"] = category
response = self.session.get(
f"{auction_url}/search", params=params
)
if self._has_captcha(response.text):
site_key = self._extract_site_key(response.text)
token = self._solve_recaptcha(site_key, f"{auction_url}/search")
response = self.session.post(
f"{auction_url}/search",
data={**params, "g-recaptcha-response": token}
)
return self._parse_listings(response.text)
def monitor_listing(self, auction_url, listing_id):
"""Get current bid and listing details."""
url = f"{auction_url}/item/{listing_id}"
response = self.session.get(url)
if self._has_captcha(response.text):
site_key = self._extract_site_key(response.text)
token = self._solve_recaptcha(site_key, url)
response = self.session.post(url, data={
"g-recaptcha-response": token
})
return self._parse_listing_detail(response.text)
def track_bids(self, auction_url, listing_ids, interval=60):
"""Track bid changes across multiple listings."""
history = {lid: [] for lid in listing_ids}
while True:
for listing_id in listing_ids:
try:
detail = self.monitor_listing(auction_url, listing_id)
previous = history[listing_id]
if previous and detail["current_bid"] != previous[-1]["current_bid"]:
print(f"Bid change on {listing_id}: "
f"${previous[-1]['current_bid']} → ${detail['current_bid']}")
history[listing_id].append(detail)
except Exception as e:
print(f"Error checking {listing_id}: {e}")
time.sleep(interval)
def _has_captcha(self, html):
return "g-recaptcha" in html or "recaptcha" in html.lower()
def _extract_site_key(self, html):
match = re.search(r'data-sitekey="([^"]+)"', html)
if match:
return match.group(1)
match = re.search(r"sitekey['\"]?\s*[:=]\s*['\"]([^'\"]+)", html)
if match:
return match.group(1)
raise ValueError("Could not find reCAPTCHA site key")
def _solve_recaptcha(self, site_key, page_url):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return data["request"]
raise TimeoutError("reCAPTCHA solve timed out")
def _parse_listings(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
def text_or_none(node):
return node.text.strip() if node and node.text else None
def attr_or_none(node, attr):
return node.get(attr) if node else None
listings = []
for item in soup.select(".listing-item, .auction-item"):
listings.append({
"title": text_or_none(item.select_one(".title")),
"current_bid": text_or_none(item.select_one(".price, .bid")),
"time_left": text_or_none(item.select_one(".time-left")),
"url": attr_or_none(item.select_one("a"), "href")
})
return listings
def _parse_listing_detail(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
def text_or_none(node):
return node.text.strip() if node and node.text else None
return {
"title": text_or_none(soup.select_one("h1, .item-title")),
"current_bid": text_or_none(soup.select_one(".current-bid, .price")),
"bid_count": text_or_none(soup.select_one(".bid-count")),
"time_left": text_or_none(soup.select_one(".time-remaining")),
"checked_at": datetime.now().isoformat()
}
# Usage
monitor = AuctionMonitor("YOUR_API_KEY")
listings = monitor.search_listings(
"https://auctions.example.com",
"vintage electronics",
category="collectibles"
)
Fiyat takibi ve uyarı sistemi (JavaScript)
İzleme listenizdeki ilanların fiyatı belirlediğiniz eşiğe yaklaştığında uyarı üretmek isterseniz, aynı çözüm akışını JavaScript tarafında kurabilirsiniz. AuctionTracker her ilanı sorgular, gerektiğinde reCAPTCHA v2'yi çözer ve fiyat sınıra ulaştığında bir uyarı listesi döndürür.
class AuctionTracker {
constructor(apiKey) {
this.apiKey = apiKey;
this.watchList = new Map();
}
addWatch(listingId, url, maxPrice) {
this.watchList.set(listingId, { url, maxPrice, history: [] });
}
async checkAll() {
const alerts = [];
for (const [id, watch] of this.watchList) {
try {
const detail = await this.fetchListing(watch.url);
watch.history.push(detail);
const price = parseFloat(detail.currentBid.replace(/[^0-9.]/g, ''));
if (price >= watch.maxPrice * 0.9) {
alerts.push({
listing: id,
price,
threshold: watch.maxPrice,
message: `Price approaching limit: $${price} / $${watch.maxPrice}`
});
}
} catch (error) {
alerts.push({ listing: id, error: error.message });
}
}
return alerts;
}
async fetchListing(url) {
const response = await fetch(url);
const html = await response.text();
if (html.includes('g-recaptcha')) {
return this.solveAndFetch(url, html);
}
return this.parseDetail(html);
}
async solveAndFetch(url, html) {
const siteKeyMatch = html.match(/data-sitekey="([^"]+)"/);
if (!siteKeyMatch) throw new Error('No reCAPTCHA site key found');
const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
method: 'POST',
body: new URLSearchParams({
key: this.apiKey,
method: 'userrecaptcha',
googlekey: siteKeyMatch[1],
pageurl: url,
json: '1'
})
});
const { request: taskId } = await submitResp.json();
for (let i = 0; i < 60; i++) {
await new Promise(r => setTimeout(r, 3000));
const result = await fetch(
`https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
);
const data = await result.json();
if (data.status === 1) {
// Resubmit with token
const response = await fetch(url, {
method: 'POST',
body: new URLSearchParams({ 'g-recaptcha-response': data.request })
});
return this.parseDetail(await response.text());
}
}
throw new Error('reCAPTCHA solve timed out');
}
parseDetail(html) {
// Parse auction listing details from HTML
return {
currentBid: html.match(/current.?bid[^>]*>([^<]+)/i)?.[1]?.trim(),
bidCount: html.match(/(\d+)\s*bids?/i)?.[1],
timeLeft: html.match(/time.?(?:left|remaining)[^>]*>([^<]+)/i)?.[1]?.trim(),
checkedAt: new Date().toISOString()
};
}
}
// Usage
const tracker = new AuctionTracker('YOUR_API_KEY');
tracker.addWatch('item-123', 'https://auctions.example.com/item/123', 500);
tracker.addWatch('item-456', 'https://auctions.example.com/item/456', 200);
const alerts = await tracker.checkAll();
İzleme sıklığını nasıl seçersiniz
Kontrol sıklığı arttıkça beklenen CAPTCHA oranı da yükselir. İhtiyacınıza göre bir denge kurun:
| Kontrol sıklığı | Kullanım örneği | Beklenen CAPTCHA oranı |
|---|---|---|
| Her 30 saniyede bir | Son dakika teklifleri | Yüksek — proxy ile istekleri dağıtın |
| Her 5 dakikada bir | Aktif açık artırma takibi | Orta |
| Her 15 dakikada bir | İzleme listesi takibi | Düşük |
| Saatte bir | Uzun vadeli fiyat araştırması | En düşük |
CAPTCHA sıklığını azaltma teknikleri
Aynı hacimde veriyi daha az doğrulamayla toplamak için istek desenlerinizi düzenleyin:
- Oturum çerezini yeniden kullanın — kimlik doğrulama durumunu korur ve her istekte yeniden doğrulama gerekmez.
- Proxy ile istekleri farklı IP'lere yayın — tek bir IP'den gelen yoğunluğu azaltır.
- İstek aralıklarını sabit tutmayın — öngörülebilir, periyodik trafik desenini zayıflatır.
- Kimliği doğrulanmış hesap kullanın — CAPTCHA tetikleme eşiğini düşürür.
Sorun giderme
| Sorun | Sebep | Düzeltme |
|---|---|---|
| Her istekte CAPTCHA çıkıyor | Oturum kalıcılığı yok | requests.Session()'ı yeniden kullanın |
| reCAPTCHA v2 token'ı reddedildi | Token'ın ömrü doldu (2 dakika) | Göndermeden hemen önce çözün |
| Listeleme sayfası 0 sonuç gösteriyor | CAPTCHA sonuçları sessizce filtreledi | Gizli CAPTCHA öğelerini kontrol edin |
| Çok sayıda CAPTCHA sonrası IP engellendi | İstek sınırı aşıldı | İstek aralıklarını artırın, proxy ile yükü dağıtın |
Maliyet ve doğru planı seçme
Açık artırma izleme genellikle sürekli çalışan bir iş akışıdır; maliyeti belirleyen şey çözdüğünüz CAPTCHA sayısı değil, kaç eşzamanlı thread'e ihtiyaç duyduğunuzdur. CaptchaAI thread başına ücretlendirir ve her planda thread başına sınırsız çözüm sunar; bu, TL'nin dalgalı seyrettiği bir ortamda öngörülebilir aylık USD maliyeti demektir.
Tek bir izleme listesini düşük sıklıkla takip eden bir otomasyon geliştiricisi için BASIC ($15/ay, 5 thread) çoğu zaman yeterlidir. Birden fazla açık artırmayı paralel izleyen, son dakika tekliflerini yakından takip eden bir iş akışında STANDARD ($30/ay, 15 thread) daha rahat bir eşzamanlılık sağlar. Fiyatlar USD üzerinden sabittir; güncel değerler için CaptchaAI fiyatlandırma sayfasına bakın.
Not: Açık artırma listelerinden topladığınız veriler kişisel veri içeriyorsa, Türkiye'de KVKK kapsamına girebilir. İzleme iş akışlarınızı yetkili olduğunuz veri ve hesaplarla sınırlı tutun.
Sık sorulan sorular
Açık artırma sitelerinde hangi CAPTCHA türleriyle karşılaşırım?
Çoğunlukla reCAPTCHA v2; bazı kategori ve gezinme sayfalarında Cloudflare Turnstile çıkabilir. CaptchaAI her ikisini de çözer, dolayısıyla tek bir entegrasyonla iki türü de yönetebilirsiniz.
reCAPTCHA v2 token'ı neden reddedildi?
En yaygın sebep süredir: token'ın kullanım ömrü yaklaşık 2 dakikadır. Token'ı isteği göndermeden hemen önce çözün ve çözüm sırasındaki pageurl ile isteğin adresi aynı olsun.
İzleme için hangi CaptchaAI planı yeterli?
Tek bir izleme listesini seyrek kontrol ediyorsanız BASIC ($15/ay, 5 thread) yeterlidir. Birden fazla açık artırmayı paralel ve sık izliyorsanız STANDARD ($30/ay, 15 thread) daha fazla eşzamanlı thread verir. Fiyatlar USD'dir.
Açık artırmanın son dakikalarında CAPTCHA'ları nasıl yönetirim?
Son dakikalarda önceden kimliği doğrulanmış bir oturumla tarayıcı otomasyonu kullanın; bu, karşılaşılan CAPTCHA sayısını azaltır. Yine de çıkan reCAPTCHA v2 doğrulamalarını CaptchaAI genellikle 60 saniyenin altında çözer.
İlgili Makaleler
- API ile reCAPTCHA v2 callback sorununu çözme
- Aynı sayfada reCAPTCHA v2 ve Turnstile yönetimi
- reCAPTCHA v2 callback mekanizması
Sonraki Adımlar
Açık artırmaları kesintisiz izlemeye bugün başlayın — CaptchaAI API anahtarınızı alın ve karşınıza çıkan reCAPTCHA v2 doğrulamalarını otomatik olarak çözün.