Visibilitas rantai pasokan memerlukan data dari ratusan portal pemasok, platform logistik, dan sistem inventaris. Banyak dari mereka melindungi data mereka di balik CAPTCHA. CaptchaAI menangani tantangan ini sehingga pemantauan saluran pipa berjalan tanpa gangguan.
Dimana CAPTCHA Memblokir Data Rantai Pasokan
| Jenis Sumber | Jenis CAPTCHA | Data | Frecookiensi |
|---|---|---|---|
| Portal pemasok | reCAPTCHA v2 | Persediaan, harga, waktu tunggu | Setiap hari |
| Operator pengiriman | Cloudflare Turnstile | Pelacakan, tarif, ETA pengiriman | Setiap jam |
| Katalog pabrikan | Gambar CAPTCHA | Spesifikasi produk, MOQ | Mingguan |
| Portal bea cukai | reCAPTCHA v2 | Tarif bea, kode tarif | Setiap hari |
| Otoritas pelabuhan | Gambar CAPTCHA | Jadwal kapal, kemacetan pelabuhan | Setiap 6 jam |
| Pertukaran komoditas | reCAPTCHA v3 | Harga spot, kontrak berjangka | Waktu nyata |
Monitor Multi-Pemasok
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))
Pemantauan Tarif Pengiriman
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 []
Peringatan Perubahan Stok
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)
Kebijakan penggantian penyedia
- Pisahkan pemasok penting dari sumber opsional sehingga satu kegagalan tidak menghapus seluruh laporan pemantauan.
- Tentukan kapan data usang dapat diterima dan kapan pemasok yang hilang harus memicu insiden eksplisit.
- Tingkatkan tekanan CAPTCHA yang terus-menerus pada pemasok karena risiko pengadaan, bukan hanya kesalahan teknis.
Kebijakan penggantian penyedia
- Pisahkan pemasok penting dari sumber opsional sehingga satu kegagalan tidak menghapus seluruh laporan pemantauan.
- Tentukan kapan data usang dapat diterima dan kapan pemasok yang hilang harus memicu insiden eksplisit.
- Tingkatkan tekanan CAPTCHA yang terus-menerus pada pemasok karena risiko pengadaan, bukan hanya kesalahan teknis.
Pemecahan Masalah
| Masalah | Penyebab | Solusi |
|---|---|---|
| Tata letak halaman pemasok diubah | Desain ulang situs | Perbarui pemilih CSS |
| CAPTCHA di setiap cek | Terlalu sering memeriksa | Tingkatkan interval antar pemeriksaan |
| Sesi berakhir di tengah pemeriksaan | Timeout portal habis | Gunakan sticky session, periksa lebih cepat |
| Nilai data hilang | Diperlukan login | Tambahkan langkah autentikasi |
| Harga yang ditampilkan salah | Penetapan harga berbasis geografis | Cocokkan lokasi proxy dengan pasar |
Pertanyaan Umum
Seberapa sering saya harus memeriksa inventaris pemasok?
Setiap hari untuk sebagian besar pemasok. Setiap jam untuk komponen penting selama kekurangan pasokan. Pemeriksaan yang terlalu sering memicu CAPTCHA lebih cepat.
Bisakah saya memantau ratusan pemasok?
Ya. Rotasi antar pemasok dengan penundaan di antara masing-masing pemasok. Gunakan proxy yang berputar untuk mendistribusikan beban ke seluruh IP.
Jenis CAPTCHA manakah yang paling umum di situs rantai pasokan?
reCAPTCHA v2 di portal pemasok, Cloudflare Turnstile di situs logistik/carrier. Situs pabrikan lama sering kali menggunakan CAPTCHA gambar.
Panduan Terkait
- Memutar egress jaringan yang diotorisasi
- Sticky Session vs Berputar
- Kegigihan Sesi Browser
Jaga agar rantai pasokan Anda tetap terlihat —dapatkan kunci CaptchaAI Andadan mengotomatiskan pengumpulan data di seluruh portal pemasok.