Casos de Uso

Web Scraping de investigación académica con resolución CAPTCHA

Las bases de datos académicas y los portales de revistas utilizan CAPTCHA para limitar el acceso automatizado. Los investigadores que realizan revisiones de literatura, análisis bibliométricos y metaestudios necesitan recopilar datos de estas fuentes a escala. CaptchaAI maneja los desafíos CAPTCHA automáticamente.


Fuentes académicas y CAPTCHA

Fuente Tipo CAPTCHA Disparador Datos
Google Académico reCAPTCHA v3 Consultas de gran volumen Citas, artículos
PubMed reCAPTCHA v2 Búsquedas repetidas Literatura biomédica
Web of Science Cloudflare Turnstile Descargas masivas Métricas de citas
Scopus reCAPTCHA v2 Operaciones de exportación Datos bibliométricos
IEEE Xplore reCAPTCHA v2 Búsqueda + descarga Artículos de ingeniería
JSTOR reCAPTCHA v2 Acceder a páginas Humanidades / Ciencias sociales

Recopilador de datos de citas

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

Análisis bibliométrico

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

Limitación de tarifas para sitios académicos

Fuente Retraso recomendado Páginas máx./hora
Google Scholar 10-15 segundos 40-50
PubMed 3-5 segundos 100
Web of Science 5-10 segundos 60
Scopus 5-10 segundos 60
IEEE 3-5 segundos 100
JSTOR 5-10 segundos 60

Los sitios académicos prohíben las IP rápidamente. Utilice retrasos conservadores.


Solución de problemas

Problema causa Solución
CAPTCHA en cada búsqueda IP marcada del sitio académico Cambiar de proxy, aumentar el retraso a más de 15 segundos
No se obtuvieron resultados En su lugar se devolvió la página CAPTCHA Verifique CAPTCHA antes de analizar
Falta el resumen Detrás del muro de pago Utilice proxy institucional o acceso abierto
Académico bloquea IP Límite de tasa excedido Espere 30 minutos, use una IP diferente
Exportación limitada El sitio limita las descargas masivas Descargar en lotes más pequeños

Preguntas frecuentes

¿Se permite el scraping de bases de datos académicas?

Los metadatos públicos (títulos, autores, resúmenes) son generalmente accesibles. El acceso al texto completo depende de la licencia. PubMed admite explícitamente el acceso programático a través de su API E-utilities. Prefiera siempre las API oficiales cuando estén disponibles.

¿Cómo evito que me bloqueen en Google Scholar?

Utilice retrasos de 10 a 15 segundos entre solicitudes, rote los proxies residenciales y limite a 50 consultas por hora. Scholar es agresivo a la hora de bloquear el acceso automatizado.

¿Puedo usar CaptchaAI con un proxy institucional?

Sí. Configure su proxy institucional para la sesión de navegación y CaptchaAI para resolver CAPTCHA; funcionan de forma independiente.


Guías relacionadas

  • Proxies residenciales rotativos
  • Inicio rápido de CaptchaAI

Acelera tu revisión de literatura. Obtén tu clave de CaptchaAI y automatiza la recopilación de datos académicos.

Los comentarios están deshabilitados para este artículo.