La verificación de anuncios requiere visitar miles de páginas web para verificar la ubicación de los anuncios, la seguridad de la marca y el cumplimiento. Muchos sitios de editores utilizan CAPTCHA que bloquean las comprobaciones automáticas. CaptchaAI mantiene en funcionamiento su proceso de verificación.
Qué verifica la verificación de anuncios
| Verificación | Descripción | Por qué los CAPTCHA lo bloquean |
|---|---|---|
| Colocación de anuncios | ¿El anuncio se muestra en la mitad superior de la página? | Las visitas automáticas a la página activan la detección de bots |
| Seguridad de la marca | Sin anuncios junto a contenido dañino | La comprobación masiva de URL se parece al raspado |
| Visibilidad | ¿Era realmente visible el anuncio? | Navegadores headless marcados por Cloudflare |
| Orientación geográfica | Anuncio correcto en la región correcta | El tráfico de proxy activa CAPTCHA |
| Seguimiento de la competencia | ¿Qué anuncios muestran los competidores? | Búsquedas de anuncios de gran volumen |
Implementación
import requests
import time
import re
import json
import os
from datetime import datetime
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
def solve_captcha(method, params):
params["key"] = API_KEY
params["method"] = method
resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
if not resp.text.startswith("OK|"):
raise Exception(resp.text)
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id,
})
if result.text == "CAPCHA_NOT_READY":
continue
if result.text.startswith("OK|"):
return result.text.split("|", 1)[1]
raise Exception(result.text)
raise TimeoutError()
def verify_ad_placement(url, session):
"""Verify ad placement on a publisher page."""
resp = session.get(url)
# Solve CAPTCHA if present
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', resp.text)
if match:
token = solve_captcha("userrecaptcha", {
"googlekey": match.group(1),
"pageurl": url,
})
resp = session.post(url, data={"g-recaptcha-response": token})
html = resp.text
# Check for ad elements
result = {
"url": url,
"timestamp": datetime.utcnow().isoformat(),
"ads_found": [],
"brand_safety": True,
"captcha_solved": match is not None,
}
# Detect ad tags
ad_patterns = [
(r'googletag\.pubads', "Google Ad Manager"),
(r'doubleclick\.net', "DFP/DoubleClick"),
(r'ad\.doubleclick', "DoubleClick"),
(r'amazon-adsystem', "Amazon Ads"),
(r'criteo\.com/.*\.js', "Criteo"),
]
for pattern, name in ad_patterns:
if re.search(pattern, html):
result["ads_found"].append(name)
# Brand safety check — flag problematic content
safety_keywords = [
"violence", "hate speech", "explicit",
"gambling", "illegal",
]
page_text = re.sub(r'<[^>]+>', '', html).lower()
for keyword in safety_keywords:
if keyword in page_text:
result["brand_safety"] = False
break
return result
def run_verification(urls, output_file="verification_report.json"):
"""Run ad verification across multiple publisher URLs."""
session = requests.Session()
session.headers["User-Agent"] = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0"
)
results = []
for i, url in enumerate(urls):
try:
result = verify_ad_placement(url, session)
results.append(result)
ads = ", ".join(result["ads_found"]) or "None"
safe = "SAFE" if result["brand_safety"] else "UNSAFE"
print(f" [{i+1}/{len(urls)}] {url}: {ads} [{safe}]")
except Exception as e:
results.append({
"url": url,
"error": str(e),
"timestamp": datetime.utcnow().isoformat(),
})
print(f" [{i+1}/{len(urls)}] {url}: ERROR - {e}")
time.sleep(2)
with open(output_file, "w") as f:
json.dump(results, f, indent=2)
# Summary
total = len(results)
safe = sum(1 for r in results if r.get("brand_safety"))
captchas = sum(1 for r in results if r.get("captcha_solved"))
errors = sum(1 for r in results if "error" in r)
print(f"\n Total: {total} | Safe: {safe} | CAPTCHAs solved: {captchas} | Errors: {errors}")
return results
# Publisher URLs to verify
publisher_urls = [
"https://publisher1.com/article/tech-news",
"https://publisher2.com/sports/latest",
"https://publisher3.com/finance/markets",
]
run_verification(publisher_urls)
Escalar con editores protegidos por Cloudflare
Muchos editores premium utilizan Cloudflare. Maneja tanto Turnstile como desafíos completos:
def handle_cloudflare(url, session):
"""Handle Cloudflare-protected publisher pages."""
resp = session.get(url)
if "cf-turnstile" in resp.text:
match = re.search(r'data-sitekey=["\']([^"\']+)', resp.text)
if match:
token = solve_captcha("turnstile", {
"sitekey": match.group(1),
"pageurl": url,
})
return session.post(url, data={
"cf-turnstile-response": token,
})
if resp.status_code == 403 and "cf-browser-verification" in resp.text:
data = solve_captcha("cloudflare_challenge", {
"pageurl": url,
"proxy": "user:pass@proxy:port",
"proxytype": "HTTP",
})
# Parse qa_validation_cookie and use same proxy
return data
return resp
Preguntas frecuentes
¿Cuántas páginas puedo verificar por hora?
Con CaptchaAI, puede verificar entre 200 y 500 páginas por hora según la frecuencia del CAPTCHA y los tiempos de resolución.
¿Funciona esto para la verificación de anuncios de video?
Este enfoque funciona para anuncios gráficos y nativos. La verificación de anuncios de vídeo normalmente requiere renderizado del navegador con Selenium o Playwright.
¿Cómo manejo las diferentes regiones?
Utilice proxies de zonas geográficas de destino. CaptchaAI admite parámetros de proxy para que el contexto de resolución coincida con su orientación geográfica.
Guías relacionadas
- Scraping de sitios web protegidos
- Proxies residenciales rotativos
- Problemas de CAPTCHA en navegadores headless