Use Cases

Scraping Data Riset Media Sosial dengan Penanganan CAPTCHA

Yang menghentikan proyek riset media sosial biasanya bukan parser HTML Anda, melainkan satu tantangan CAPTCHA di halaman login atau di hasil pencarian. Alurnya sebenarnya pendek: deteksi sitekey di halaman, kirim ke API CaptchaAI, tempelkan token yang kembali ke request berikutnya, lalu lanjutkan pengumpulan data seperti biasa.

Di bawah ini: peta CAPTCHA per platform, kode scraper Python untuk reCAPTCHA v2 dan Turnstile, ritme request yang wajar, plus hitungan biaya untuk agensi riset kecil di Jakarta yang anggarannya harus tetap datar.


Tentukan dulu ruang lingkup data Anda

Sebelum menulis satu baris scraper, kunci dulu apa yang boleh masuk dataset:

  • Hanya data publik. Profil, postingan, dan statistik yang bisa dilihat siapa pun tanpa masuk sebagai orang lain.
  • API resmi lebih dulu. Kalau platform menyediakan API dengan field yang Anda butuhkan, pakai itu — lebih stabil dan sesuai Ketentuan Layanan.
  • Minimalkan data pribadi. UU Pelindungan Data Pribadi (UU 27/2022) dan UU ITE membuat pengumpulan data pribadi tanpa dasar pemrosesan yang jelas menjadi risiko nyata bagi tim riset di Indonesia. Simpan agregat dan teks postingan, bukan identitas perorangan. Ini catatan kepatuhan, bukan nasihat hukum.
  • Hormati batas laju. Ritme request yang sopan menurunkan frekuensi CAPTCHA jauh lebih efektif daripada trik apa pun di sisi klien.

Peta CAPTCHA di platform sosial

Peta ini menentukan method mana yang Anda kirim ke in.php.

Platform Jenis CAPTCHA Kapan biasanya muncul Konteks
Instagram reCAPTCHA v2 Login, pencarian, akses profil Pembatasan laju permintaan
Facebook reCAPTCHA v2 Login, pencarian berulang Checkpoint keamanan
Twitter/X Cloudflare Turnstile Login, akses API Pencegahan bot
TikTok reCAPTCHA v3 Tampilan profil, pencarian Penilaian kualitas trafik
LinkedIn Cloudflare Challenge Pengambilan data profil Deteksi bot
Reddit reCAPTCHA v2 Login, penjelajahan intensif Pencegahan penyalahgunaan

Semua tipe di atas didukung CaptchaAI: reCAPTCHA v3 selesai di bawah 4 detik, Cloudflare Turnstile di bawah 10 detik, Cloudflare Challenge di bawah 15 detik, dan reCAPTCHA v2 di bawah 60 detik, dengan tingkat keberhasilan tinggi pada tipe yang didukung. Kalau target Anda memakai hCaptcha atau FunCaptcha, berhenti di sini: keduanya belum didukung, dan GeeTest v4 baru berstatus segera hadir.


Scraper riset sosial dengan penanganan CAPTCHA otomatis

Kelas berikut menyatukan satu sesi HTTP yang konsisten, satu fungsi penyelesaian yang dipakai ulang, dan deteksi tantangan pada tiap respons — dengan pola empat langkah yang sama seperti integrasi CaptchaAI lainnya: kirim task ke in.php, simpan task ID, polling res.php, pakai token.

import requests
import time
import re

CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"


def solve_captcha(method, sitekey, pageurl, **kwargs):
    data = {
        "key": CAPTCHAAI_KEY,
        "method": method,
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    }
    data.update(kwargs)
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=data)
    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,
        })
        r = result.json()
        if r["request"] != "CAPCHA_NOT_READY":
            return r["request"]
    raise TimeoutError("Solve timeout")


class SocialMediaResearcher:
    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 (iPhone; CPU iPhone OS 17_5 like Mac OS X) "
            "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 "
            "Mobile/15E148 Safari/604.1",
            "Accept-Language": "en-US,en;q=0.9",
        })

    def authenticate(self, login_url, credentials, sitekey):
        """Login with CAPTCHA handling."""
        # Load login page
        self.session.get(login_url)

        # Solve CAPTCHA
        token = solve_captcha("userrecaptcha", sitekey, login_url)

        # Submit login
        resp = self.session.post(login_url, data={
            **credentials,
            "g-recaptcha-response": token,
        })
        return resp.status_code == 200

    def collect_profiles(self, profile_urls):
        """Collect public profile data with CAPTCHA handling."""
        profiles = []

        for url in profile_urls:
            try:
                resp = self.session.get(url, timeout=30)

                # Handle CAPTCHA if triggered
                if self._has_captcha(resp.text):
                    resp = self._handle_captcha(resp.text, url)

                profiles.append({
                    "url": url,
                    "data": self._parse_profile(resp.text),
                    "status": "success",
                })
                time.sleep(5)  # Slow down between profiles

            except Exception as e:
                profiles.append({
                    "url": url,
                    "error": str(e),
                    "status": "failed",
                })

        return profiles

    def _has_captcha(self, html):
        return any(tag in html.lower() for tag in [
            'data-sitekey', 'g-recaptcha', 'cf-turnstile',
            'challenge-platform', 'captcha',
        ])

    def _handle_captcha(self, html, url):
        match = re.search(r'data-sitekey="([^"]+)"', html)
        if not match:
            return self.session.get(url)

        sitekey = match.group(1)

        if 'cf-turnstile' in html:
            token = solve_captcha("turnstile", sitekey, url)
            return self.session.post(url, data={"cf-turnstile-response": token})
        else:
            token = solve_captcha("userrecaptcha", sitekey, url)
            return self.session.post(url, data={"g-recaptcha-response": token})

    def _parse_profile(self, html):
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, "html.parser")
        return {
            "name": self._safe_text(soup, "h1, .profile-name"),
            "bio": self._safe_text(soup, ".bio, .profile-bio"),
            "followers": self._safe_text(soup, "[data-followers], .followers"),
            "posts": self._safe_text(soup, "[data-posts], .posts-count"),
        }

    def _safe_text(self, soup, selector):
        el = soup.select_one(selector)
        return el.get_text(strip=True) if el else ""

Dua detail yang sering terlewat. _has_captcha memeriksa penanda seperti data-sitekey, g-recaptcha, dan cf-turnstile sebelum Anda membuang waktu mem-parsing halaman verifikasi. Dan nama field token harus cocok dengan jenis tantangan: g-recaptcha-response untuk reCAPTCHA, cf-turnstile-response untuk Turnstile. Salah field berarti token valid tetapi request tetap ditolak.


Mengumpulkan postingan per hashtag untuk analisis tren

Riset tren butuh volume postingan per tagar, bukan profil satu per satu. Fungsi berikut menelusuri beberapa halaman hasil dan menangani tantangan di tengah jalan tanpa memutus sesi.

def research_hashtag(hashtag, platform_url, pages=5):
    """Collect posts for a specific hashtag."""
    researcher = SocialMediaResearcher(
        proxy="http://user:pass@mobile.proxy.com:5000"
    )

    all_posts = []
    for page in range(pages):
        url = f"{platform_url}/explore/tags/{hashtag}?page={page}"
        resp = researcher.session.get(url, timeout=30)

        if researcher._has_captcha(resp.text):
            resp = researcher._handle_captcha(resp.text, url)

        from bs4 import BeautifulSoup
        soup = BeautifulSoup(resp.text, "html.parser")
        posts = soup.select(".post-item, article")
        for post in posts:
            all_posts.append({
                "text": post.get_text(strip=True)[:500],
                "hashtag": hashtag,
                "page": page,
            })

        time.sleep(5)

    return all_posts

Jalankan terjadwal dan simpan hasilnya mentah dulu; normalisasi teks sebaiknya jadi tahap terpisah.


Memantau penyebutan merek setiap hari

Ini kasus yang paling sering dipesan klien agensi di Indonesia: laporan harian berisi berapa kali sebuah merek disebut di beberapa platform, dipecah per kata kunci.

import json
from datetime import datetime


class BrandMonitor:
    def __init__(self, brand_name, keywords, proxy=None):
        self.brand = brand_name
        self.keywords = keywords
        self.researcher = SocialMediaResearcher(proxy=proxy)

    def daily_scan(self, platform_urls):
        """Run daily brand mention scan across platforms."""
        report = {
            "brand": self.brand,
            "date": datetime.now().isoformat(),
            "platforms": {},
        }

        for name, url in platform_urls.items():
            mentions = []
            for keyword in self.keywords:
                search_url = f"{url}/search?q={keyword}"
                try:
                    resp = self.researcher.session.get(search_url, timeout=30)

                    if self.researcher._has_captcha(resp.text):
                        resp = self.researcher._handle_captcha(
                            resp.text, search_url,
                        )

                    from bs4 import BeautifulSoup
                    soup = BeautifulSoup(resp.text, "html.parser")
                    results = soup.select(".search-result, .post")
                    mentions.append({
                        "keyword": keyword,
                        "count": len(results),
                    })
                    time.sleep(5)
                except Exception as e:
                    mentions.append({
                        "keyword": keyword,
                        "error": str(e),
                    })

            report["platforms"][name] = mentions

        return report


# Usage
monitor = BrandMonitor(
    brand_name="CaptchaAI",
    keywords=["captchaai", "captcha ai", "captcha solver"],
    proxy="http://user:pass@mobile.proxy.com:5000",
)
report = monitor.daily_scan({
    "twitter": "https://twitter-alternative.example.com",
    "reddit": "https://www.reddit.com",
})
print(json.dumps(report, indent=2))

Karena pemindaian harian berjalan tanpa pengawasan, catat kegagalan per kata kunci alih-alih menghentikan seluruh proses: laporan dengan tiga kata kunci gagal masih berguna.


Ritme request dan durasi sesi yang wajar

Frekuensi tantangan berbanding lurus dengan agresivitas pola akses Anda. Angka berikut adalah titik awal konservatif, bukan janji.

Platform Jeda antar request Durasi sesi sebelum jeda panjang
Instagram 1 request / 10 detik Maks 5 menit
Facebook 1 request / 5 detik Maks 10 menit
Twitter/X 1 request / 3 detik Maks 15 menit
TikTok 1 request / 5 detik Maks 5 menit
LinkedIn 1 request / 10 detik Maks 5 menit
Reddit 1 request / 2 detik Maks 30 menit

Dua catatan pelengkap. Gunakan egress jaringan yang diotorisasi dan konsisten selama satu sesi berjalan — berpindah jalur keluar di tengah sesi hampir selalu memicu tantangan baru. Lalu cocokkan lokasi jaringan dengan audiens yang diteliti; untuk deployment, region seperti AWS ap-southeast-1 (Singapura) atau ap-southeast-3 (Jakarta) memberi latensi yang masuk akal bagi target Indonesia.


Biaya: dihitung per thread, bukan per penyelesaian

CaptchaAI menagih per thread berjalan, dengan penyelesaian tanpa batas selama bulan berjalan. Biaya Anda ditentukan oleh berapa banyak CAPTCHA yang diselesaikan bersamaan, bukan berapa totalnya.

Freelancer yang menjalankan pemindaian merek harian untuk dua atau tiga klien umumnya cukup dengan BASIC ($15/bulan, 5 thread). Agensi riset dengan beberapa pipeline di jam yang sama biasanya naik ke STANDARD ($30/bulan, 15 thread), sementara tim data yang mengumpulkan data sepanjang hari cocok di ADVANCE ($90/bulan, 50 thread). Semua harga dalam USD.

Karena tidak ada biaya per CAPTCHA, menambah kata kunci atau tagar tidak menaikkan tagihan.


Masalah umum dan cara menanganinya

Gejala Penyebab paling mungkin Penanganan
CAPTCHA di hampir setiap request Pola akses terlalu rapat Perbesar jeda, perpendek sesi
Halaman kembali kosong Konten di balik login Autentikasi dulu, atau ganti sumber
Token diterima tetapi request ditolak Field token salah g-recaptcha-response atau cf-turnstile-response
Cloudflare Challenge berulang Sinyal browser tidak konsisten Puppeteer/Playwright konfigurasi standar
Batas waktu tercapai saat polling Batas percobaan terlalu pendek Jeda 5 detik, perpanjang percobaan

Pertanyaan umum

Bagaimana kalau platform target memakai hCaptcha atau FunCaptcha?

Berhenti di situ. hCaptcha dan FunCaptcha (Arkose Labs) tidak didukung, dan GeeTest v4 baru berstatus segera hadir. Yang didukung dan relevan di sini: reCAPTCHA v2 (termasuk Invisible dan Enterprise), reCAPTCHA v3, Cloudflare Turnstile, Cloudflare Challenge, GeeTest v3, serta image CAPTCHA. CaptchaFox (beta), Friendly Captcha (beta), dan Lemin (beta) masih berstatus beta.

Berapa lama satu tantangan diselesaikan?

Bergantung tipenya: reCAPTCHA v3 di bawah 4 detik, Turnstile di bawah 10 detik, Cloudflare Challenge di bawah 15 detik, reCAPTCHA v2 di bawah 60 detik. Itu batas atas layanan, jadi jangan menetapkan timeout 15 detik untuk reCAPTCHA v2.

Paket mana yang masuk akal untuk pemindaian harian ratusan profil?

Hitung dari konkurensi, bukan total. Kalau scraper hanya memproses lima halaman bersamaan, BASIC ($15/bulan, 5 thread) sudah cukup meski total profilnya ribuan. Naikkan paket ketika thread menjadi antrean yang menahan pipeline.

Bagaimana cara menurunkan jumlah CAPTCHA yang perlu diselesaikan?

Perbesar jeda antar request, pertahankan satu sesi dan satu jalur keluar selama pengumpulan, dan hentikan permintaan berulang ke endpoint pencarian yang sama. Penanganan otomatis lewat API adalah jaring pengaman, bukan pengganti pola akses yang wajar.


Bacaan lanjutan


Jangan biarkan riset sosial Anda berhenti di halaman verifikasi — ambil API key CaptchaAI dan tangani reCAPTCHA v2, reCAPTCHA v3, serta Cloudflare Turnstile lewat satu fungsi.

Komentar dinonaktifkan untuk artikel ini.