تتطلب رؤية سلسلة التوريد بيانات من مئات بوابات الموردين، ومنصات الخدمات اللوجستية، وأنظمة المخزون. العديد من هؤلاء يقومون بحماية بياناتهم خلف اختبارات CAPTCHA. يتعامل CaptchaAI مع هذه التحديات بحيث تعمل مراقبة خطوط الأنابيب دون انقطاع.
لكن نجاح هذا النوع من المراقبة يعتمد على ترتيب الأولويات بقدر اعتماده على حل CAPTCHA نفسه. بوابة مورد حرج لمكوّن ناقص يجب أن تُعامل بشكل مختلف عن كتالوج يُحدَّث أسبوعيًا أو مسار شحن لا يتغير إلا كل عدة ساعات.
كيف تحدد أولويات المراقبة؟
| نوع المصدر | الأولوية المعتادة | وتيرة منطقية | لماذا؟ |
|---|---|---|---|
| الموردون الحرجون للمخزون | عالية | كل ساعة أو عند حدث | أي نقص أو تأخير يؤثر مباشرة على التخطيط |
| أسعار الشحن والناقلات | متوسطة إلى عالية | كل ساعة | التكاليف والمواعيد تتغير خلال اليوم |
| كتالوجات المصنعين | متوسطة | يوميًا أو أسبوعيًا | التغييرات أبطأ عادة |
| بوابات الجمارك أو الرسوم | متوسطة | يوميًا | الهدف متابعة الامتثال والتكلفة لا التغير اللحظي |
حيث تقوم اختبارات CAPTCHA بحظر بيانات سلسلة التوريد
| نوع المصدر | نوع التحقق | البيانات | التردد |
|---|---|---|---|
| بوابات الموردين | reCAPTCHA v2 | المخزون والتسعير والمهل الزمنية | يوميا |
| ناقلات الشحن | Cloudflare Turnstile | التتبع والأسعار ومواعيد التسليم المتوقعة | كل ساعة |
| كتالوجات الشركة المصنعة | صورة التحقق | مواصفات المنتج، موك | أسبوعيا |
| البوابات الجمركية | reCAPTCHA v2 | معدلات الرسوم، رموز التعريفة الجمركية | يوميا |
| سلطات الموانئ | صورة التحقق | جداول السفن وازدحام الموانئ | كل 6 ساعات |
| تبادل السلع | reCAPTCHA v3 | الأسعار الفورية، العقود الآجلة | في الوقت الحقيقي |
مراقب متعدد الموردين
import requests
import time
import re
import json
import base64
from datetime import datetime
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
def solve_recaptcha(sitekey, pageurl):
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
"key": CAPTCHAAI_KEY, "method": "userrecaptcha",
"googlekey": sitekey, "pageurl": pageurl, "json": 1,
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
data = result.json()
if data["request"] != "CAPCHA_NOT_READY":
return data["request"]
raise TimeoutError("Timeout")
def solve_turnstile(sitekey, pageurl):
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
"key": CAPTCHAAI_KEY, "method": "turnstile",
"sitekey": sitekey, "pageurl": pageurl, "json": 1,
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
data = result.json()
if data["request"] != "CAPCHA_NOT_READY":
return data["request"]
raise TimeoutError("Timeout")
def solve_image(image_bytes):
img_b64 = base64.b64encode(image_bytes).decode()
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
"key": CAPTCHAAI_KEY, "method": "base64",
"body": img_b64, "json": 1,
})
task_id = resp.json()["request"]
for _ in range(20):
time.sleep(3)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
data = result.json()
if data["request"] != "CAPCHA_NOT_READY":
return data["request"]
raise TimeoutError("Timeout")
class SupplyChainMonitor:
def __init__(self, suppliers, proxy=None):
self.suppliers = suppliers
self.session = requests.Session()
if proxy:
self.session.proxies = {"http": proxy, "https": proxy}
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
})
def check_all(self):
"""Check inventory and pricing across all suppliers."""
report = {
"timestamp": datetime.now().isoformat(),
"suppliers": {},
}
for supplier in self.suppliers:
try:
data = self._check_supplier(supplier)
report["suppliers"][supplier["name"]] = {
"status": "success",
"data": data,
}
except Exception as e:
report["suppliers"][supplier["name"]] = {
"status": "error",
"error": str(e),
}
time.sleep(3)
return report
def _check_supplier(self, supplier):
url = supplier["url"]
resp = self.session.get(url, timeout=30)
# Handle CAPTCHA based on type
captcha_type = supplier.get("captcha_type")
if captcha_type and self._has_captcha(resp.text):
resp = self._solve_captcha(resp, url, supplier)
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
return {
"products": self._extract_inventory(soup),
"last_updated": self._extract_date(soup),
}
def _has_captcha(self, html):
return any(tag in html.lower() for tag in [
'data-sitekey', 'g-recaptcha', 'cf-turnstile', 'captcha',
])
def _solve_captcha(self, resp, url, supplier):
captcha_type = supplier.get("captcha_type", "recaptcha")
sitekey = supplier.get("sitekey", "")
if not sitekey:
match = re.search(r'data-sitekey="([^"]+)"', resp.text)
sitekey = match.group(1) if match else ""
if captcha_type == "turnstile":
token = solve_turnstile(sitekey, url)
return self.session.post(url, data={"cf-turnstile-response": token})
elif captcha_type == "image":
match = re.search(r'src="(/captcha[^"]+)"', resp.text)
if match:
img_resp = self.session.get(url.rstrip("/") + match.group(1))
answer = solve_image(img_resp.content)
return self.session.post(url, data={"captcha": answer})
else:
token = solve_recaptcha(sitekey, url)
return self.session.post(url, data={"g-recaptcha-response": token})
return resp
def _extract_inventory(self, soup):
items = []
for row in soup.select("table.inventory tr, .product-row"):
cols = row.select("td, .col")
if len(cols) >= 3:
items.append({
"sku": cols[0].get_text(strip=True),
"stock": cols[1].get_text(strip=True),
"price": cols[2].get_text(strip=True),
})
return items
def _extract_date(self, soup):
date_el = soup.select_one(".last-updated, .update-time")
return date_el.get_text(strip=True) if date_el else ""
# Configure suppliers
suppliers = [
{
"name": "Supplier A",
"url": "https://supplier-a.example.com/inventory",
"captcha_type": "recaptcha",
"sitekey": "6Lc_xxxxxxx",
},
{
"name": "Carrier B",
"url": "https://carrier-b.example.com/rates",
"captcha_type": "turnstile",
"sitekey": "0x4AAAAAAA_xxx",
},
{
"name": "Manufacturer C",
"url": "https://manufacturer-c.example.com/catalog",
"captcha_type": "image",
},
]
monitor = SupplyChainMonitor(
suppliers=suppliers,
proxy="http://user:pass@residential.proxy.com:5000",
)
report = monitor.check_all()
print(json.dumps(report, indent=2))
مراقبة معدل الشحن
class ShippingRateTracker:
def __init__(self, proxy=None):
self.session = requests.Session()
if proxy:
self.session.proxies = {"http": proxy, "https": proxy}
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
})
def get_rates(self, carrier_url, origin, destination, weight):
"""Fetch shipping rates, handling Turnstile CAPTCHA."""
resp = self.session.get(carrier_url, timeout=30)
sitekey_match = re.search(r'data-sitekey="([^"]+)"', resp.text)
if sitekey_match:
token = solve_turnstile(sitekey_match.group(1), carrier_url)
resp = self.session.post(carrier_url, data={
"origin": origin,
"destination": destination,
"weight": weight,
"cf-turnstile-response": token,
})
if resp.status_code == 200:
return resp.json().get("rates", [])
return []
التنبيه على تغييرات المخزون
def monitor_with_alerts(monitor, alert_thresholds, check_interval=3600):
"""Continuously monitor and alert on inventory changes."""
previous_data = {}
while True:
report = monitor.check_all()
for supplier, info in report["suppliers"].items():
if info["status"] != "success":
continue
for product in info["data"].get("products", []):
sku = product["sku"]
stock = product.get("stock", "")
# Parse stock level
try:
stock_qty = int(re.sub(r'\D', '', stock))
except ValueError:
continue
key = f"{supplier}:{sku}"
prev_qty = previous_data.get(key, stock_qty)
threshold = alert_thresholds.get(sku, 10)
if stock_qty < threshold and prev_qty >= threshold:
print(f"ALERT: {supplier} - {sku} dropped to {stock_qty}")
previous_data[key] = stock_qty
time.sleep(check_interval)
استكشاف الأخطاء وإصلاحها
| المشكلة | السبب | الإجراء |
|---|---|---|
| تم تغيير تخطيط صفحة المورد | إعادة تصميم الموقع | تحديث محددات CSS |
| CAPTCHA على كل شيك | التحقق بشكل متكرر | زيادة الفاصل الزمني بين الشيكات |
| تنتهي الجلسة في منتصف الفحص | مهلة البوابة | استخدم الجلسة اللزجة، وتحقق بشكل أسرع |
| بيانات السعر مفقودة | تسجيل الدخول مطلوب | إضافة خطوة المصادقة |
| عرض أسعار خاطئة | التسعير على أساس الجغرافي | مطابقة موقع الوكيل بالسوق |
الأسئلة الشائعة
كم مرة يجب أن أتحقق من مخزون الموردين؟
يوميا لمعظم الموردين. كل ساعة للمكونات الهامة أثناء نقص الإمدادات. تؤدي عمليات التحقق المتكررة جدًا إلى تشغيل اختبارات CAPTCHA بشكل أسرع.
هل يمكنني مراقبة مئات الموردين؟
نعم. التناوب بين الموردين مع وجود تأخيرات بين كل منهم. استخدم الوكلاء الدوارين لتوزيع الحمل عبر عناوين IP.
ما هو نوع CAPTCHA الأكثر شيوعًا في مواقع سلسلة التوريد؟
reCAPTCHA v2 على بوابات الموردين، Cloudflare Turnstile على مواقع الخدمات اللوجستية/carrier. غالبًا ما تستخدم مواقع الشركات المصنعة القديمة اختبارات CAPTCHA للصور.
أدلة ذات صلة
- تناوب الوكلاء السكنيين: أفضل الممارسات لحل اختبار CAPTCHA
- الجلسات الثابتة مقابل الجلسات الدورية: أفضل استراتيجية وكيل لاختبارات CAPTCHA
استخدم CaptchaAI ضمن جدول مراقبة واقعي يفرّق بين المورد الحرج والمصدر البطيء التحديث، حتى تظل الرؤية التشغيلية مفيدة بدل أن تتحول إلى ضجيج أو حمل زائد على البوابات.