Use Cases

Scraping Data Penelitian Akademik dengan Pemecahan CAPTCHA

Dosen yang mengejar skor Sinta atau syarat kenaikan jabatan fungsional tahu betul rasanya: membuka satu per satu halaman Scopus atau Web of Science untuk menghitung sitasi, lalu terhenti oleh reCAPTCHA begitu permintaan kelima atau keenam dikirim dalam semenit. Google Scholar, PubMed, IEEE Xplore, dan JSTOR punya pola serupa — begitu volume kueri naik, CAPTCHA muncul untuk membatasi akses otomatis. CaptchaAI menyelesaikan tantangan itu di tengah alur crawler, sehingga pengumpulan sitasi, abstrak, dan metadata jurnal tetap berjalan tanpa harus diklik manual satu per satu.


Peta CAPTCHA di Basis Data Akademik

Setiap portal memicu jenis CAPTCHA yang berbeda tergantung polanya. Kenali dulu petanya sebelum menulis crawler:

  • Google Scholar — reCAPTCHA v3, dipicu kueri bervolume tinggi, menjaga data kutipan dan makalah.
  • PubMed — reCAPTCHA v2, dipicu pencarian berulang, melindungi literatur biomedis.
  • Web of Science — Cloudflare Turnstile, dipicu unduhan massal, membatasi metrik kutipan.
  • Scopus — reCAPTCHA v2, dipicu operasi ekspor, melindungi data bibliometrik.
  • IEEE Xplore — reCAPTCHA v2, dipicu kombinasi cari + unduh, menjaga makalah teknik.
  • JSTOR — reCAPTCHA v2, dipicu akses halaman berulang, melindungi literatur humaniora/ilmu sosial.

Studi Kasus: Scraping Data Sitasi untuk Sinta dan Akreditasi

Kasus yang sering muncul di kalangan dosen dan peneliti Indonesia: laporan Beban Kerja Dosen (BKD) atau borang akreditasi program studi meminta bukti sitasi Scopus dan Web of Science yang terverifikasi, biasanya untuk ratusan publikasi sekaligus. Mengumpulkannya manual — buka halaman, catat angka sitasi, ulangi — bisa memakan berhari-hari, apalagi begitu Scopus mulai menampilkan reCAPTCHA v2 setelah beberapa kali ekspor berturut-turut.

Crawler pada bagian berikut mengotomatiskan proses itu: mengambil metadata dan jumlah sitasi dari puluhan hingga ratusan entri, lalu mengekspornya ke CSV yang tinggal dicocokkan dengan borang. Untuk volume seperti ini, paket BASIC CaptchaAI ($15/bulan, 5 thread) biasanya cukup untuk satu basis data. Kalau crawler jalan paralel di Scopus, Web of Science, dan PubMed sekaligus, paket STANDARD ($30/bulan, 15 thread) memberi headroom tanpa biaya tambahan per solve. Tim yang menjalankan crawler dari region Asia Tenggara — AWS ap-southeast-1 (Singapura) atau GCP asia-southeast2 (Jakarta) — tetap perlu memperhitungkan latensi tambahan ke basis data yang di-hosting di AS/Eropa; jeda antar-permintaan yang lebih longgar (lihat tabel di bagian bawah) membantu menutup selisih itu. Sebagai catatan kepatuhan, batasi pengambilan pada metadata publik saja — judul, penulis, abstrak, jumlah sitasi — sejalan dengan semangat UU Pelindungan Data Pribadi (UU 27/2022).


Script Python: Crawler Akademik yang Menyelesaikan CAPTCHA Otomatis

Fungsi solve_captcha di bawah mengikuti alur empat langkah yang sama dipakai di semua integrasi CaptchaAI:

  1. Kirim task ke in.php dengan sitekey dan pageurl.
  2. Simpan task_id dari respons.
  3. Polling res.php setiap 5 detik sampai token siap.
  4. Pasang token ke permintaan asli dan kirim ulang.

Contoh berikut memakai requests dan BeautifulSoup untuk crawler dasar. Begitu AcademicScraper mendeteksi elemen data-sitekey, g-recaptcha, atau cf-turnstile di HTML, alur di atas berjalan otomatis lewat _solve_and_retry:

import requests
import time
import re
from bs4 import BeautifulSoup
import csv

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("Timeout")


class AcademicScraper:
    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",
            "Accept-Language": "en-US,en;q=0.9",
        })

    def search_papers(self, search_url, query, max_pages=10):
        """Search academic database for papers matching query."""
        all_papers = []

        for page in range(max_pages):
            url = f"{search_url}?q={query}&start={page * 10}"
            resp = self.session.get(url, timeout=30)

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

            papers = self._parse_results(resp.text)
            if not papers:
                break  # No more results

            all_papers.extend(papers)
            print(f"Page {page + 1}: {len(papers)} papers")
            time.sleep(5)  # Respectful delay

        return all_papers

    def get_paper_details(self, paper_url):
        """Get detailed metadata for a single paper."""
        resp = self.session.get(paper_url, timeout=30)

        if self._has_captcha(resp.text):
            resp = self._solve_and_retry(resp.text, paper_url)

        soup = BeautifulSoup(resp.text, "html.parser")
        return {
            "title": self._safe_text(soup, "h1, .article-title"),
            "authors": self._safe_text(soup, ".authors, .author-list"),
            "abstract": self._safe_text(soup, ".abstract, #abstract"),
            "doi": self._safe_text(soup, ".doi, [data-doi]"),
            "journal": self._safe_text(soup, ".journal-name, .publication"),
            "year": self._safe_text(soup, ".pub-date, .year"),
            "citations": self._safe_text(soup, ".citation-count, .cited-by"),
        }

    def export_to_csv(self, papers, filename):
        """Export collected papers to CSV."""
        if not papers:
            return
        keys = papers[0].keys()
        with open(filename, "w", newline="", encoding="utf-8") as f:
            writer = csv.DictWriter(f, fieldnames=keys)
            writer.writeheader()
            writer.writerows(papers)
        print(f"Exported {len(papers)} papers to {filename}")

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

    def _solve_and_retry(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_results(self, html):
        soup = BeautifulSoup(html, "html.parser")
        papers = []
        for item in soup.select(".gs_r, .search-result, article.result"):
            title_el = item.select_one("h3 a, .result-title a")
            if title_el:
                papers.append({
                    "title": title_el.get_text(strip=True),
                    "url": title_el.get("href", ""),
                    "snippet": self._safe_text(item, ".gs_rs, .abstract-snippet"),
                    "authors": self._safe_text(item, ".gs_a, .author-info"),
                })
        return papers

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


# Usage — Literature review
scraper = AcademicScraper(
    proxy="http://user:pass@residential.proxy.com:5000"
)

papers = scraper.search_papers(
    "https://scholar.example.com/scholar",
    query="machine learning CAPTCHA solving",
    max_pages=5,
)

# Get details for top papers
detailed = []
for paper in papers[:20]:
    if paper["url"]:
        detail = scraper.get_paper_details(paper["url"])
        detailed.append(detail)
        time.sleep(3)

scraper.export_to_csv(detailed, "literature_review.csv")

Sesuaikan selector CSS (.gs_r, .search-result, article.result) dengan struktur HTML basis data yang ditarget — tiap portal jurnal punya markup berbeda, jadi cek dulu lewat "view source" sebelum menjalankan crawler dalam skala penuh.


Membangun Jaringan Sitasi dengan Analisis Bibliometrik

Untuk pemetaan literatur yang lebih dalam — melacak siapa mengutip siapa — fungsi berikut menelusuri tautan "cited by" secara rekursif dan membangun jaringan sitasi:

def bibliometric_analysis(scraper, seed_papers, depth=2):
    """Follow citations to build a citation network."""
    visited = set()
    network = []

    def _crawl(paper_url, current_depth):
        if current_depth > depth or paper_url in visited:
            return
        visited.add(paper_url)

        try:
            details = scraper.get_paper_details(paper_url)
            network.append(details)

            # Follow "cited by" links
            resp = scraper.session.get(f"{paper_url}/citations", timeout=30)
            if scraper._has_captcha(resp.text):
                resp = scraper._solve_and_retry(resp.text, f"{paper_url}/citations")

            citations = scraper._parse_results(resp.text)
            for cite in citations[:5]:  # Limit breadth
                if cite["url"]:
                    _crawl(cite["url"], current_depth + 1)
                    time.sleep(3)

        except Exception as e:
            print(f"Error crawling {paper_url}: {e}")

    for paper in seed_papers:
        _crawl(paper["url"], 0)

    return network

Batasi depth ke 2 kecuali benar-benar perlu — tiap level tambahan melipatgandakan jumlah permintaan (dan tantangan CAPTCHA) secara eksponensial.


Atur Kecepatan Crawler agar Tidak Kena Blokir

Basis data akademik menandai IP yang mengirim permintaan terlalu cepat. Tabel berikut jadi acuan jeda aman per sumber:

Sumber Jeda yang Disarankan Maks Halaman/Jam
Google Scholar 10-15 detik 40-50
PubMed 3-5 detik 100
Web of Science 5-10 detik 60
Scopus 5-10 detik 60
IEEE 3-5 detik 100
JSTOR 5-10 detik 60

Situs akademik cenderung memblokir IP dengan cepat begitu polanya mencurigakan — pakai jeda konservatif, terutama untuk Google Scholar yang paling sensitif terhadap kueri beruntun.


Solusi untuk Masalah Umum saat Scraping Akademik

  1. CAPTCHA muncul di setiap pencarian — situs akademik menandai IP Anda. Ganti proxy dan tingkatkan jeda hingga 15+ detik.
  2. Tidak ada hasil yang dikembalikan — halaman CAPTCHA dikembalikan, bukan hasil pencarian. Periksa keberadaan CAPTCHA sebelum menguraikan HTML.
  3. Abstrak hilang dari hasil — konten di balik dinding berbayar (paywall). Gunakan proxy institusi atau cari versi akses terbuka.
  4. Google Scholar memblokir IP — batas laju permintaan terlampaui. Tunggu 30 menit, lalu ganti IP.
  5. Ekspor data terbatas — situs membatasi unduhan massal dalam satu sesi. Unduh dalam batch yang lebih kecil.

Pertanyaan Umum

Metadata publik — judul, penulis, abstrak, jumlah sitasi — umumnya boleh diakses dan dikumpulkan. Akses ke teks lengkap tetap tunduk pada lisensi masing-masing penerbit. PubMed secara eksplisit menyediakan API E-utilities resmi untuk akses terprogram; pakai itu lebih dulu sebelum scraping HTML. Untuk kepatuhan terhadap UU Pelindungan Data Pribadi, batasi pengumpulan hanya pada metadata publik dan hindari data pribadi di luar yang sudah dipublikasikan penerbit.

Bagaimana data sitasi ini membantu laporan Sinta atau akreditasi jurnal?

Dosen dan peneliti yang mengejar skor Sinta atau syarat kenaikan jabatan fungsional sering perlu memverifikasi jumlah sitasi Scopus atau Web of Science satu per satu secara manual. Crawler pada panduan ini mengumpulkan data itu otomatis lintas ratusan entri, lalu diekspor ke CSV yang tinggal dicocokkan dengan laporan BKD atau borang akreditasi.

Berapa biaya menjalankan crawler riset akademik dengan CaptchaAI?

CaptchaAI memakai skema thread, bukan per-solve. Untuk satu basis data dengan volume ratusan kueri per hari, paket BASIC ($15/bulan, 5 thread) umumnya cukup. Kalau crawler jalan paralel di beberapa basis data sekaligus, paket STANDARD ($30/bulan, 15 thread) atau ADVANCE ($90/bulan, 50 thread) memberi headroom tanpa biaya tambahan per solve.

Berapa lama waktu penyelesaian CAPTCHA saat crawler mengirim ribuan kueri akademik?

Tergantung tipe CAPTCHA yang dipicu situs. reCAPTCHA v3 di Google Scholar biasanya tuntas dalam hitungan detik (di bawah 4 detik), reCAPTCHA v2 di PubMed/Scopus/IEEE/JSTOR di bawah 60 detik, dan Cloudflare Turnstile di Web of Science di bawah 10 detik — semuanya dengan tingkat keberhasilan tinggi pada tipe yang didukung. Untuk ribuan kueri, jumlah thread pada paket Anda menentukan berapa banyak permintaan yang diproses paralel, bukan waktu solve per token.

Bisakah CaptchaAI dipakai bersama proxy kampus atau institusi?

Ya. Proxy institusi menangani akses jaringan dan otentikasi ke basis data berlangganan, sementara CaptchaAI menangani penyelesaian tantangan CAPTCHA — keduanya berjalan independen dan bisa dipasang bersamaan dalam satu stack scraping.


Panduan Terkait


Percepat pengumpulan data sitasi untuk riset atau laporan akreditasi Anda — ambil API key CaptchaAI dan biarkan crawler jalan tanpa terhambat CAPTCHA.

Komentar dinonaktifkan untuk artikel ini.