خط مراقبة الأسعار الناجح ليس الذي يجمع السعر في الظروف المثالية، بل الذي لا يتوقف حين يظهر اختبار CAPTCHA فجأة على صفحة المنتج. الحل عمليًا هو إضافة طبقة واحدة إلى خط المعالجة: عند اكتشاف تحدٍّ، أرسله إلى CaptchaAI، احصل على الرمز، أعد تحميل الصفحة، ثم تابع استخراج السعر كأن شيئًا لم يحدث.
هذا الدليل يعرض النمط كاملًا — البنية، وكود Python وNode.js، والجدولة، وتقدير التكلفة — لمراقبة مصرّح بها على متاجر تملك حق متابعتها أو اختبارها.
متى تظهر اختبارات CAPTCHA أمام أدوات مراقبة الأسعار
نادرًا ما يظهر التحدي في أول طلب. يبدأ بالظهور عند ارتفاع معدل الطلبات، أو تكرار الزيارات من عنوان IP واحد، أو الوصول إلى صفحات حساسة مثل نتائج البحث وتدفق إتمام الشراء. يختلف نوع التحقق باختلاف المنصة:
| منصة | نوع التحقق | متى يظهر التحدي |
|---|---|---|
| أمازون | صورة CAPTCHA، reCAPTCHA | ارتفاع حجم الطلب |
| وول مارت | Cloudflare Turnstile | كشف البوت |
| eBay | reCAPTCHA v2 | أنماط طلب غير معتادة |
| Best Buy | Cloudflare Challenge | ارتفاع واضح في المرور الآلي |
| متاجر شوبيفاي | reCAPTCHA v3 | يختلف حسب تكوين المتجر |
من دون طبقة معالجة صريحة، لا يُظهر خط المراقبة خطأً واضحًا؛ بل يخزّن صفحة التحدي بدل صفحة المنتج، فتظهر فجوات صامتة في بيانات التسعير يصعب تفسيرها بعد أيام. اكتشاف التحدي مبكرًا وحلّه في المسار نفسه هو ما يحافظ على سلامة السلسلة الزمنية للأسعار.
تنبيه امتثال: استخدم هذا النمط فقط على المواقع التي تملك إذنًا لمراقبتها أو اختبارها، ومع معدل طلبات مسؤول يتوافق مع الشروط التشغيلية المسموح بها.
سيناريو من السوق المحلي
تخيّل فريق تسعير في متجر إلكترونيات بالرياض أو دبي يتابع أسعار المنافسين على متاجر إقليمية ودولية قبل مواسم الذروة مثل الجمعة البيضاء وعروض رمضان. في هذه الفترات ترتفع وتيرة الفحص من مرة كل ساعة إلى مرة كل بضع دقائق، فتبدأ صفحات البحث في عرض reCAPTCHA v2 أو تحديات Cloudflare. من دون معالجة تلقائية، يتوقف التحديث عند أهم لحظة يحتاج فيها الفريق إلى بيانات دقيقة. مع إضافة CaptchaAI إلى الخط، يستمر جمع الأسعار بالعملة المعروضة (بالدولار الأمريكي حين تعرضها المتاجر بالدولار)، وتبقى لوحة المقارنة محدّثة طوال الموسم دون تدخل يدوي.
بنية خط المراقبة
الفكرة أن يبقى الحل خطوة اختيارية داخل المسار: نجلب الصفحة أولًا، وإن ظهر تحدٍّ نحلّه ثم نعيد المحاولة، وإن لم يظهر ننتقل مباشرة إلى استخراج السعر.
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
التنفيذ العملي
مراقب الأسعار بلغة Python
الدالة solve_captcha تُرسل التحدي إلى in.php ثم تستطلع النتيجة دوريًا من res.php حتى تعود جاهزة. أما fetch_with_captcha فتفحص الصفحة بحثًا عن مفتاح موقع reCAPTCHA أو Turnstile، وتحلّه ثم تعيد إرسال الطلب مع الرمز الناتج قبل استخراج السعر:
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)
التنفيذ عبر Node.js
النمط نفسه بأسلوب غير متزامن: نرسل التحدي، نستطلع النتيجة في حلقة، ثم نعيد تحميل الصفحة عبر Axios ونحلّل الـ HTML باستخدام cheerio لاستخراج السعر:
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, ""));
}
جدولة عمليات الفحص
المراقبة قيمتها في انتظامها. شغّل الفحص كل 30 دقيقة عبر cron حتى يعمل مستقلًا عن جلستك:
# crontab -e
*/30 * * * * cd /opt/monitor && python price_monitor.py >> /var/log/prices.log 2>&1
أو أبقِ الجدولة داخل العملية نفسها عبر مكتبة schedule في Python حين تريد التحكم بالتوقيت برمجيًا:
import schedule
schedule.every(30).minutes.do(lambda: monitor_prices(products))
while True:
schedule.run_pending()
time.sleep(60)
اضبط الفاصل الزمني بحسب حساسية السلعة: المنتجات سريعة التغيّر تستحق فحصًا أكثف، بينما يكفي الفحص كل ساعة أو أكثر للفئات المستقرة، وهو ما يقلّل عدد التحديات والتكلفة معًا.
كم تكلّف المراقبة؟
يعتمد الاستهلاك على عدد الصفحات التي تُظهر تحديًا فعليًا، لا على عدد الصفحات المفحوصة:
| الحجم | CAPTCHAs/Day | التكلفة اليومية التقريبية |
|---|---|---|
| 50 منتجًا، كل 30 دقيقة | ~2400 | ~2-5 دولارات |
| 200 منتج كل 15 دقيقة | ~19,200 | ~ 15-30 دولارًا |
| 1000 منتج في الساعة | ~24000 | ~20-40 دولارًا |
لا تؤدي جميع عمليات تحميل الصفحات إلى تشغيل اختبارات CAPTCHA، لذا قد تكون التكاليف الفعلية أقل بنسبة 50-70%. ومن المهم فهم نموذج التسعير: يحتسب CaptchaAI الاشتراك على عدد الـ Threads المتزامنة وليس على كل عملية حل، وكل خطة تشمل حلولًا غير محدودة لكل Thread خلال الشهر. لتشغيل 5–10 عمال متزامنين كما في البنية أعلاه، تكفي خطة ADVANCE ($90 شهريًا، 50 Thread)، بينما يبدأ التسعير من خطة BASIC ($15 شهريًا، 5 Threads) للمشاريع الأصغر.
ممارسات لتشغيل مستقر
- وزّع الطلبات على مدار اليوم بدل إرسالها دفعة واحدة، فالانفجار المفاجئ في المرور هو أكثر ما يستدعي ظهور التحديات.
- خزّن آخر سعر معروف لكل منتج، وميّز بين "لا تغيير" و"فشل الجلب" حتى لا تُفسَّر فجوة تقنية على أنها ثبات في السعر.
- راقب معدل ظهور التحديات كمؤشر تشغيلي: ارتفاعه المفاجئ غالبًا يعني تشديدًا في كشف البوت يستدعي خفض الوتيرة.
- افصل منطق الحل عن منطق الاستخراج، فطبقة CAPTCHA مستقلة تسهّل صيانة محدِّدات السعر عند تغيّر تصميم المتجر.
- سجّل كل محاولة مع الطابع الزمني ورمز الحالة لتتبّع الموثوقية عبر الزمن ومعرفة أي متجر يستهلك أكبر قدر من الحلول.
الأسئلة الشائعة
ما أنواع CAPTCHA التي أحتاج إلى التعامل معها على متاجر التجزئة؟
غالبًا reCAPTCHA v2 وv3، وCloudflare Turnstile وChallenge، وأحيانًا صور CAPTCHA على صفحات البحث. جميع هذه الأنواع مدعومة في CaptchaAI، ويكتشف الكود المفتاح تلقائيًا ويرسله بالطريقة المناسبة.
كيف أتعامل مع reCAPTCHA v3 الذي يعمل بالخلفية بلا نقرة؟
يعتمد reCAPTCHA v3 على درجة ثقة بدل تحدٍّ ظاهر، لذا يُرسَل بنفس أسلوب userrecaptcha ويعاد الرمز الناتج مع الطلب. أبقِ الوتيرة معقولة، لأن سلوك الطلبات نفسه هو ما يؤثر في الدرجة قبل مرحلة الحل.
كم عدد الـ Threads الذي أحتاجه لمراقبة مئات المنتجات؟
يتحدد بعدد العمال المتزامنين لا بعدد المنتجات؛ فمع 5–10 عمال متزامنين تكفي خطة ADVANCE ($90 شهريًا، 50 Thread) بمساحة كافية، ويمكن التوسّع لاحقًا حسب حجم الفحص.
هل يبقى الحساب آمنًا من الحظر بعد حل اختبار CAPTCHA؟
حلّ التحدي جزء واحد من المعادلة. التزم بسياسات المتجر، ووزّع الطلبات بوتيرة مسؤولة، واعتمد على التخزين المؤقت، واعمل ضمن نطاق مصرّح به بدل رفع عدوانية الإرسال.