Los medios de comunicación y las plataformas de medios utilizan CAPTCHA para proteger el contenido de la agregación automatizada. Los supervisores de los medios, las empresas de relaciones públicas y las organizaciones de investigación deben recopilar artículos de forma programática. CaptchaAI maneja los desafíos CAPTCHA en todas las fuentes de noticias.
CAPTCHA en plataformas de noticias
| Tipo de fuente | CAPTCHA | gatillo | Contenido |
|---|---|---|---|
| Principales medios de comunicación | Cloudflare Turnstile | Detección de robots | Artículos, titulares |
| Servicios de cable (AP, Reuters) | reCAPTCHA v2 | Acceso masivo | noticias de última hora |
| Publicaciones de pago | reCAPTCHA v3 | Intentos de acceso | Artículos premium |
| Sitios de noticias locales | reCAPTCHA v2 | Limitación de velocidad | noticias regionales |
| Agregadores de noticias | Cloudflare Challenge | Detección de raspado | Feeds agregados |
| Sitios de comunicados de prensa | CAPTCHA de imagen | Descargar paginas | contenido de relaciones públicas |
Agregador de noticias
import requests
import time
import re
from bs4 import BeautifulSoup
from datetime import datetime
import json
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 NewsAggregator:
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 collect_headlines(self, source_url, section=None):
"""Collect headlines from a news source."""
url = f"{source_url}/{section}" if section else source_url
resp = self.session.get(url, timeout=30)
if self._has_captcha(resp.text):
resp = self._solve_and_retry(resp.text, url)
soup = BeautifulSoup(resp.text, "html.parser")
articles = []
for item in soup.select("article, .story, .headline-item, h2 a, h3 a"):
link = item if item.name == "a" else item.select_one("a")
if link:
articles.append({
"title": link.get_text(strip=True),
"url": self._abs_url(source_url, link.get("href", "")),
"source": source_url,
"collected_at": datetime.now().isoformat(),
})
return articles
def get_article(self, article_url):
"""Fetch full article content."""
resp = self.session.get(article_url, timeout=30)
if self._has_captcha(resp.text):
resp = self._solve_and_retry(resp.text, article_url)
soup = BeautifulSoup(resp.text, "html.parser")
# Remove unwanted elements
for tag in soup.select("script, style, nav, footer, .ad, .sidebar"):
tag.decompose()
content_el = soup.select_one(
"article, .article-body, .story-body, .entry-content"
)
return {
"url": article_url,
"title": self._text(soup, "h1, .article-title"),
"author": self._text(soup, ".author, .byline, [rel='author']"),
"date": self._text(soup, "time, .publish-date, .article-date"),
"content": content_el.get_text(separator="\n", strip=True) if content_el else "",
"word_count": len(content_el.get_text().split()) if content_el else 0,
}
def aggregate_sources(self, sources, max_articles_per=20):
"""Aggregate headlines across multiple sources."""
all_articles = []
for source in sources:
try:
articles = self.collect_headlines(source["url"], source.get("section"))
all_articles.extend(articles[:max_articles_per])
print(f"{source['name']}: {len(articles)} headlines")
except Exception as e:
print(f"{source['name']}: Error - {e}")
time.sleep(3)
return all_articles
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})
token = solve_captcha("userrecaptcha", sitekey, url)
return self.session.post(url, data={"g-recaptcha-response": token})
def _text(self, soup, selector):
el = soup.select_one(selector)
return el.get_text(strip=True) if el else ""
def _abs_url(self, base, href):
if href.startswith("http"):
return href
return base.rstrip("/") + "/" + href.lstrip("/")
# Usage
aggregator = NewsAggregator(
proxy="http://user:pass@residential.proxy.com:5000"
)
sources = [
{"name": "Tech News A", "url": "https://technews-a.example.com", "section": "latest"},
{"name": "Business B", "url": "https://business-b.example.com", "section": "tech"},
{"name": "Industry C", "url": "https://industry-c.example.com"},
]
headlines = aggregator.aggregate_sources(sources)
print(f"Total: {len(headlines)} headlines collected")
Presupuesto por dominio para no quemar la fuente
| Tipo de fuente | Cadencia sugerida | Señal para frenar |
|---|---|---|
| Home / portada | 1 consulta cada 3 a 5 minutos | Aparición de CAPTCHA en la portada |
| Sección temática | 1 consulta cada 5 a 10 minutos | Respuestas 403 o cambios bruscos de DOM |
| Artículo individual | Solo bajo demanda | CAPTCHA al cargar contenido ya conocido |
Monitoreo de noticias basado en palabras clave
class NewsMonitor:
def __init__(self, keywords, sources, proxy=None):
self.keywords = [kw.lower() for kw in keywords]
self.aggregator = NewsAggregator(proxy=proxy)
self.sources = sources
self.seen_urls = set()
def scan(self):
"""Scan for articles matching keywords."""
headlines = self.aggregator.aggregate_sources(self.sources)
matches = []
for article in headlines:
if article["url"] in self.seen_urls:
continue
title_lower = article["title"].lower()
matched_kws = [kw for kw in self.keywords if kw in title_lower]
if matched_kws:
article["matched_keywords"] = matched_kws
matches.append(article)
self.seen_urls.add(article["url"])
return matches
def continuous_monitor(self, interval_min=30):
"""Run continuous monitoring with alerts."""
while True:
matches = self.scan()
if matches:
print(f"\n=== {len(matches)} new matches found ===")
for m in matches:
print(f" [{', '.join(m['matched_keywords'])}] {m['title']}")
print(f" {m['url']}")
else:
print(f"No new matches at {datetime.now().strftime('%H:%M')}")
time.sleep(interval_min * 60)
# Monitor for specific topics
monitor = NewsMonitor(
keywords=["captcha", "bot detection", "web scraping", "automation"],
sources=sources,
proxy="http://user:pass@residential.proxy.com:5000",
)
matches = monitor.scan()
Solución de problemas
| Problema | causa | Solución |
|---|---|---|
| Cloudflare bloquea todas las solicitudes | Detección agresiva de bots | Utilice red residencial autorizada + UA realista |
| Muro de pago en lugar de artículo | Contenido detrás de la suscripción | Detectar muro de pago, omitir o manejar |
| CAPTCHA en cada página | IP marcada | rotar salidas de red autorizadas, agregar retrasos de más de 5 segundos |
| Contenido del artículo vacío | Contenido renderizado en JS | Utilice Selenium/Puppeteer para sitios SPA |
| Artículos duplicados | La misma historia de múltiples fuentes | Deduplicar por similitud de título |
Preguntas frecuentes
¿Es legal la agregación de noticias?
La recopilación de titulares y metadatos para investigación o seguimiento es una práctica común. La reproducción completa de artículos protegidos por derechos de autor sin permiso no lo es. Utilice fragmentos y enlace a la fuente original.
¿Cómo manejo el contenido de pago?
Detecte el muro de pago (busque clases CSS de muro de pago o longitud de contenido limitada) y márquelo. Accede únicamente al contenido que estás autorizado a ver.
¿Qué tipo de proxy funciona mejor para los sitios de noticias?
Los poderes residenciales rotativos funcionan mejor. Los principales medios de comunicación utilizan Cloudflare, que bloquea agresivamente las direcciones IP de los centros de datos.
Guías relacionadas
- Representantes residenciales rotativos
- Investigación de redes sociales
Noticias agregadas de cualquier fuente.obtenga su clave CaptchaAIy automatizar la recopilación de contenido.