Toda revisão de literatura em larga escala esbarra no mesmo obstáculo: depois de algumas dezenas de requisições, o Google Acadêmico, o PubMed ou o Web of Science passam a exigir um desafio CAPTCHA a cada página. Quem faz bibliometria, meta-análise ou mapeamento sistemático de citações não pode parar o pipeline para resolver isso manualmente. A saída é integrar a resolução automática ao próprio coletor: a API da CaptchaAI recebe o desafio, devolve o token e o script segue coletando.
Este guia mostra onde cada base acadêmica costuma acionar o CAPTCHA, como montar um coletor de dados de citação em Python e como manter os limites de requisição sob controle para não ser bloqueado.
Onde o CAPTCHA trava a coleta de dados acadêmicos
Cada base tem um gatilho diferente — algumas reagem a volume de consultas, outras a downloads em lote. Conhecer o gatilho ajuda a decidir onde investir no atraso entre requisições.
| Fonte | Tipo de CAPTCHA | Gatilho | Dados |
|---|---|---|---|
| Google Acadêmico | reCAPTCHA v3 | Consultas de alto volume | Citações, artigos |
| PubMed | reCAPTCHA v2 | Pesquisas repetidas | Literatura biomédica |
| Web of Science | Cloudflare Turnstile | Downloads em massa | Métricas de citação |
| Scopus | reCAPTCHA v2 | Operações de exportação | Dados bibliométricos |
| IEEE Xplore | reCAPTCHA v2 | Busca + download | Artigos de engenharia |
| JSTOR | reCAPTCHA v2 | Acesso a páginas | Humanidades/ciências sociais |
Como montar um coletor de dados de citação em Python
O coletor abaixo faz três coisas: busca artigos por consulta, verifica se a resposta veio com um desafio CAPTCHA embutido e, se veio, resolve o desafio antes de reenviar a requisição. A função solve_captcha encapsula a chamada à API da CaptchaAI — envia o desafio para in.php e faz polling em res.php até o token voltar pronto ou o tempo limite estourar.
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:[email protected]: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")
Repare que _has_captcha só olha para três marcadores no HTML (data-sitekey, g-recaptcha, cf-turnstile). Isso é suficiente para as seis fontes da tabela acima, porque nenhuma delas usa hCaptcha ou FunCaptcha — tipos que a CaptchaAI hoje não suporta. Se você adaptar o coletor para outra base acadêmica, confirme o tipo de desafio antes de assumir que o mesmo fluxo funciona.
Mapeando a rede de citações com análise bibliométrica
Depois de coletar o primeiro lote de artigos, um passo comum em bibliometria é seguir os links "citado por" para reconstruir a rede de citações ao redor de um tema. A função abaixo reaproveita o mesmo AcademicScraper e faz a busca em profundidade, resolvendo CAPTCHA novamente sempre que a página de citações aciona um desafio.
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
Mantenha depth baixo (2 já cobre a maioria dos mapeamentos de área) — cada nível multiplica o número de páginas visitadas e, com ele, a chance de acionar um novo CAPTCHA a cada salto.
Quanto esperar de cada fonte: limites de requisição recomendados
| Fonte | Atraso recomendado | Máximo de páginas/hora |
|---|---|---|
| Google Acadêmico | 10–15 s | 40–50 |
| PubMed | 3–5 s | 100 |
| Web of Science | 5–10 s | 60 |
| Scopus | 5–10 s | 60 |
| IEEE | 3–5 s | 100 |
| JSTOR | 5–10 s | 60 |
Sites acadêmicos banem IPs rapidamente — em geral mais rápido que um site de e-commerce comum. Trate esses números como teto, não como meta: comece mais conservador e só reduza o atraso depois de confirmar que a fonte não está sinalizando o seu IP.
No Brasil, boa parte do acesso a essas bases acontece via VPN institucional — o caso mais comum é o Portal de Periódicos da CAPES, que centraliza o login para dezenas de editoras. A técnica descrita aqui não muda nesse cenário: o proxy institucional cuida da sessão autenticada e a CaptchaAI resolve o desafio, de forma independente uma da outra. Vale também lembrar que, se a coleta envolver dados de autores, e-mails ou afiliações institucionais, as obrigações da LGPD sobre tratamento de dados pessoais se aplicam da mesma forma que em qualquer outro projeto de coleta — trate isso como parte do desenho do pipeline, não como detalhe posterior.
Problemas comuns na coleta acadêmica
Antes de ajustar código, vale checar se o problema é de fato o CAPTCHA ou algo anterior a ele — os dois sintomas mais comuns (nenhum resultado retornado e resumo faltando) têm causas diferentes.
| Problema | Causa | Correção |
|---|---|---|
| CAPTCHA em toda pesquisa | IP sinalizado pela base acadêmica | Trocar de proxy, aumentar o atraso para 15 s ou mais |
| Nenhum resultado retornado | A resposta é a própria página de CAPTCHA | Verificar CAPTCHA antes de fazer o parsing |
| Resumo (abstract) faltando | Conteúdo atrás de paywall | Usar proxy institucional ou fonte de acesso aberto |
| Base bloqueia o IP | Limite de requisições excedido | Aguardar 30 minutos, trocar de IP |
| Exportação limitada | O site limita downloads em massa | Baixar em lotes menores |
Perguntas frequentes
Posso coletar dados de bases acadêmicas de forma automatizada?
Metadados públicos (títulos, autores, resumos) geralmente são acessíveis. O acesso ao texto completo depende do licenciamento de cada editora. O PubMed, por exemplo, oferece explicitamente acesso programático pela API E-utilities — prefira sempre uma API oficial quando ela existir.
O reCAPTCHA v3 do Google Acadêmico exige alguma configuração diferente do v2?
Sim. O reCAPTCHA v3 não mostra um quadro de seleção para o usuário clicar — ele roda em segundo plano e retorna uma pontuação de risco. Na prática, para o coletor isso significa passar method="userrecaptcha" com a sitekey correta e tratar o token da mesma forma; a diferença fica na frequência das requisições, porque pontuações baixas tendem a aparecer quando o padrão de acesso foge do de um usuário humano.
O que fazer quando o resumo do artigo não aparece mesmo depois de resolver o CAPTCHA?
Normalmente é paywall, não CAPTCHA. Resolver o desafio te devolve o acesso à página; se o conteúdo completo ainda estiver bloqueado, o problema é licenciamento — use acesso institucional ou a versão em acesso aberto do artigo, quando existir.
O proxy institucional da minha universidade funciona junto com a CaptchaAI?
Sim. Configure o proxy institucional na sessão de navegação e a chave da CaptchaAI na resolução de CAPTCHA — as duas coisas funcionam de forma independente, uma não interfere na outra.
Existe limite de quantas requisições por hora eu posso enviar à API da CaptchaAI?
O limite prático não vem da CaptchaAI, e sim da base acadêmica que você está consultando (veja a tabela de atrasos recomendados acima). A API processa cada desafio enviado; quem define o ritmo seguro de requisições é o comportamento anti-bot do site de origem.
Leia também
- Proxies residenciais rotativos para resolução de CAPTCHA
- Como a qualidade do proxy afeta a taxa de resolução
Acelere sua revisão de literatura — crie sua chave da CaptchaAI e automatize a coleta de dados acadêmicos.