Use Cases

Pengumpulan Data Riset Pasar dengan Penanganan CAPTCHA

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.

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.

Panduan terkait

Komentar dinonaktifkan untuk artikel ini.