Hambatan terbesar saat mengumpulkan data riset pasar biasanya bukan parsing HTML, melainkan CAPTCHA yang muncul di halaman ulasan, direktori bisnis, dan database paten tepat saat scraper Anda mulai serius. Jawabannya sederhana: selipkan satu langkah penyelesaian CAPTCHA otomatis ke dalam pipeline, lalu biarkan collector berjalan. Artikel ini menunjukkan cara memasang CaptchaAI di jalur pengumpulan data — mendeteksi sitekey, mengirim task ke API, dan menempelkan token ke request — sehingga saluran data untuk analisis kompetitor tetap mengalir.
Pendekatannya berbasis API murni, jadi berjalan dengan klien HTTP apa pun tanpa perlu menjalankan browser penuh. Untuk halaman yang memang mewajibkan rendering, pola yang sama tinggal Anda tempelkan di dalam Puppeteer, Playwright, atau Selenium.
Sumber data riset pasar dan CAPTCHA yang menghadangnya
Sebelum menulis satu baris kode pun, petakan dulu sumber Anda ke jenis proteksinya. Tabel di bawah adalah kombinasi yang paling sering ditemui tim riset saat scraping data pasar:
| Jenis sumber | Contoh | Jenis CAPTCHA |
|---|---|---|
| Situs ulasan | G2, Trustpilot, Yelp | reCAPTCHA v2/v3 |
| Job board | LinkedIn, Indeed | Cloudflare Challenge |
| Direktori bisnis | Yellow Pages, Crunchbase | Turnstile, reCAPTCHA |
| Media sosial | Twitter/X, Reddit | Beragam |
| Database paten | USPTO, Google Patents | reCAPTCHA v2 |
| Data pemerintah | Filing SEC, sensus | Image CAPTCHA |
Semua tipe di kolom kanan — reCAPTCHA v2/v3, Cloudflare Turnstile, Cloudflare Challenge, dan image CAPTCHA — termasuk yang didukung CaptchaAI, sehingga satu integrasi bisa menangani mayoritas sumber sekaligus. Perlu dicatat: sebagian situs memakai hCaptcha, dan hCaptcha belum didukung, jadi rencanakan sumber alternatif jika target utama Anda memakainya.
Membangun pipeline pengumpulan data
Inti integrasinya adalah satu fungsi solve_captcha yang mengikuti frame empat langkah CaptchaAI: kirim task ke in.php, simpan task ID, polling res.php sampai siap, lalu pakai token. Class MarketResearchCollector di bawah membungkusnya menjadi collector yang mendeteksi reCAPTCHA maupun Turnstile secara otomatis di setiap halaman, mengekstrak ulasan dan profil perusahaan, lalu mengekspor hasilnya ke CSV.
import requests
import time
import re
import csv
import os
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
def solve_captcha(params):
params["key"] = API_KEY
resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
if not resp.text.startswith("OK|"):
raise Exception(f"Submit: {resp.text}")
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/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: {result.text}")
raise TimeoutError()
class MarketResearchCollector:
def __init__(self):
self.session = requests.Session()
self.session.headers["User-Agent"] = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0"
)
def fetch(self, url):
"""Fetch a page, solving CAPTCHAs as needed."""
resp = self.session.get(url)
# Detect reCAPTCHA
match = re.search(
r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', resp.text
)
if match:
token = solve_captcha({
"method": "userrecaptcha",
"googlekey": match.group(1),
"pageurl": url,
})
resp = self.session.post(url, data={
"g-recaptcha-response": token,
})
# Detect Turnstile
match = re.search(
r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', resp.text
)
if match and "cf-turnstile" in resp.text:
token = solve_captcha({
"method": "turnstile",
"sitekey": match.group(1),
"pageurl": url,
})
resp = self.session.post(url, data={
"cf-turnstile-response": token,
})
return resp.text
def collect_reviews(self, urls):
"""Collect review data from multiple pages."""
reviews = []
for url in urls:
try:
html = self.fetch(url)
page_reviews = self._parse_reviews(html)
reviews.extend(page_reviews)
print(f" Collected {len(page_reviews)} reviews from {url}")
time.sleep(2) # Polite delay
except Exception as e:
print(f" Error on {url}: {e}")
return reviews
def collect_company_profiles(self, urls):
"""Collect company profile data."""
profiles = []
for url in urls:
try:
html = self.fetch(url)
profile = self._parse_profile(html)
if profile:
profiles.append(profile)
print(f" Collected: {profile.get('name', 'Unknown')}")
time.sleep(2)
except Exception as e:
print(f" Error on {url}: {e}")
return profiles
def _parse_reviews(self, html):
"""Extract review data from HTML."""
reviews = []
# Generic review extraction patterns
for match in re.finditer(
r'class="review-text"[^>]*>(.*?)</div>', html, re.DOTALL
):
reviews.append({
"text": match.group(1).strip()[:500],
})
return reviews
def _parse_profile(self, html):
"""Extract company profile from HTML."""
name = re.search(r'<h1[^>]*>(.*?)</h1>', html)
desc = re.search(
r'class="description"[^>]*>(.*?)</div>', html, re.DOTALL
)
return {
"name": name.group(1).strip() if name else None,
"description": desc.group(1).strip()[:300] if desc else None,
}
def export_csv(self, data, filename):
"""Export collected data to CSV."""
if not data:
return
keys = data[0].keys()
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=keys)
writer.writeheader()
writer.writerows(data)
print(f"Exported {len(data)} records to {filename}")
Perhatikan pola deteksinya: fetch menarik halaman lebih dulu, mencari data-sitekey di HTML, dan hanya memanggil solve_captcha bila CAPTCHA benar-benar ada. Halaman tanpa proteksi langsung lewat tanpa biaya waktu tambahan — penting saat Anda memproses ribuan URL dan hanya sebagian yang memicu tantangan.
Menjalankan collector
Setelah class siap, pemakaiannya tinggal memberi daftar URL dan memanggil metode yang sesuai. Contoh di bawah mengumpulkan ulasan pesaing lalu profil perusahaan, masing-masing diekspor ke file CSV terpisah:
collector = MarketResearchCollector()
# Collect competitor reviews
review_urls = [
"https://example-reviews.com/product/competitor-a",
"https://example-reviews.com/product/competitor-b",
"https://example-reviews.com/product/competitor-c",
]
reviews = collector.collect_reviews(review_urls)
collector.export_csv(reviews, "competitor_reviews.csv")
# Collect company profiles
profile_urls = [
"https://example-directory.com/company/alpha-corp",
"https://example-directory.com/company/beta-inc",
]
profiles = collector.collect_company_profiles(profile_urls)
collector.export_csv(profiles, "company_profiles.csv")
Skenario nyata di tim riset
Pola yang sama menopang beberapa alur kerja riset yang umum dijalankan agensi data dan tim startup:
- Intelijen harga kompetitif. Pantau harga pesaing di berbagai platform e-commerce dan lacak perubahan harga, promosi, serta ketersediaan stok seiring waktu.
- Analisis sentimen merek. Kumpulkan ulasan dan rating dari beragam platform review, lalu gabungkan menjadi satu skor sentimen lintas sumber.
- Analisis pasar kerja. Scraping posting lowongan untuk memetakan tren rekrutmen, kisaran gaji, dan permintaan skill di industri Anda.
- Riset lanskap paten. Kumpulkan filing paten dari database publik untuk melacak arah inovasi dan aktivitas R&D pesaing.
Sebagai gambaran lokal: banyak pekerjaan scraping di Indonesia berjalan sebagai kontrak freelance (gaya Upwork/Fastwork) atau di agensi price-monitoring yang sangat sensitif terhadap biaya. Di sinilah model thread CaptchaAI terasa pas — biaya bulanan tetap berapa pun volume solve, sehingga sebuah proyek riset musiman tidak meledak biayanya hanya karena satu situs mendadak lebih agresif memasang CAPTCHA.
Menskalakan pengumpulan data
Begitu volume naik, dua hal yang menentukan stabilitas adalah jarak antar-request dan deduplikasi. Rekomendasi praktis:
| Faktor | Rekomendasi |
|---|---|
| Jarak request | 2–5 detik antar halaman |
| Collector paralel | 5–10 untuk skala menengah |
| Rotasi proxy | Diperlukan untuk 100+ halaman/jam |
| Deduplikasi data | Dedup berbasis hash sebelum penyimpanan |
| Penjadwalan | Jalankan harian atau mingguan untuk data tren |
Untuk deployment, menempatkan collector di region yang dekat dengan target — misalnya AWS ap-southeast-3 (Jakarta) atau ap-southeast-1 (Singapura) — memangkas latensi jaringan, meski waktu penyelesaian CAPTCHA sendiri ditentukan oleh sisi CaptchaAI, bukan oleh region Anda. Karena setiap thread menangani satu CAPTCHA in-flight, jumlah collector paralel yang efektif sebaiknya Anda selaraskan dengan jumlah thread pada paket yang dipakai.
Pertanyaan yang sering diajukan
CAPTCHA apa saja yang muncul di sumber riset pasar, dan mana yang didukung CaptchaAI?
Paling sering Anda akan bertemu reCAPTCHA v2/v3, Cloudflare Turnstile, Cloudflare Challenge, dan image CAPTCHA — semuanya didukung CaptchaAI, jadi satu integrasi menutup mayoritas sumber. Yang perlu diantisipasi: hCaptcha dan FunCaptcha belum didukung, dan GeeTest v4 masih berstatus segera hadir.
Berapa thread yang saya butuhkan untuk scraping harian?
CaptchaAI menagih per thread konkuren, bukan per solve, jadi yang menentukan bukan berapa banyak CAPTCHA yang Anda selesaikan, melainkan berapa yang berjalan bersamaan. Untuk collector skala menengah (5–10 paralel), paket BASIC ($15/bulan, 5 thread) atau STANDARD ($30/bulan, 15 thread) umumnya cukup, dengan solve tak terbatas selama sebulan.
Apakah pengumpulan data ini legal di Indonesia?
Scraping data publik umumnya diperbolehkan, tetapi tetap patuhi terms of service situs dan regulasi setempat. Di Indonesia, UU Pelindungan Data Pribadi (UU 27/2022) dan UU ITE membuat prinsip "hanya olah data yang berhak Anda proses, hindari data pribadi" menjadi acuan penting — ini bukan nasihat hukum, konsultasikan kasus spesifik Anda.
Bagaimana menjaga kualitas data agar tidak penuh duplikat?
Terapkan deduplikasi berbasis hash sebelum menyimpan, misalnya hash dari kombinasi nama entitas dan teks ulasan, lalu lewati record yang hash-nya sudah ada. Untuk data tren, simpan cap waktu setiap pengambilan agar perubahan antar-jadwal bisa dibandingkan tanpa menimpa data lama.
Bagaimana jika sebuah situs memblokir collector sepenuhnya?
Gabungkan penyelesaian CAPTCHA CaptchaAI dengan rotasi egress jaringan yang diotorisasi dan pola request yang wajar — jeda antar-halaman yang realistis dan User-Agent yang konsisten. Blokir total biasanya soal reputasi IP, bukan sekadar CAPTCHA.