← SCRAM AI Lab
Los portales SAT/IMSS detectan headless browsers. Combinación ganadora: undetected-chromedriver para Python + Playwright para flow control. 2captcha y nunca almacenar credenciales del cliente.
May 21, 2026
6 lecturas
Los portales del SAT, IMSS, REPSE e Infonavit fueron diseñados en 2008 y desde entonces les han pegado parches anti-bot. Detectan Selenium clásico, headless Chrome y user agents genéricos en menos de 3 segundos. Los webdriver.navigator tags están marcados, las fingerprints de canvas se comparan contra blacklists, y el timing de los clicks es analizado. Si vas a hacer RPA serio sobre estos sitios, el stack que aguanta producción en 2026 es undetected-chromedriver (Python) + Playwright para flow control + 2captcha para los retos visuales.
La combinación undetected-chromedriver con Playwright como controlador resuelve: UC parchea las firmas del navegador, Playwright orquesta el flow con su API más robusta que Selenium.
# requirements.txt
playwright==1.49.0
undetected-playwright-patch==1.40.0
2captcha-python==1.5.1
fastapi==0.115.0
rq==2.0.0
redis==5.2.0
from undetected_playwright import stealth_async
from playwright.async_api import async_playwright
from twocaptcha import TwoCaptcha
async def login_sat(rfc: str, password: str, captcha_solver: TwoCaptcha):
async with async_playwright() as p:
browser = await p.chromium.launch(
headless=False, # headed gana
args=['--disable-blink-features=AutomationControlled'],
)
context = await browser.new_context(
locale='es-MX',
timezone_id='America/Mexico_City',
user_agent=REAL_CHROME_UA,
)
await stealth_async(context)
page = await context.new_page()
await page.goto('https://www.sat.gob.mx/...')
await page.fill('#rfc', rfc)
await page.fill('#password', password)
# captcha image
captcha_src = await page.locator('img.captcha').get_attribute('src')
result = captcha_solver.normal(captcha_src)
await page.fill('#captcha', result['code'])
await page.click('#submit')
await page.wait_for_url('**/dashboard', timeout=30000)
Los portales gubernamentales tiran 503 durante la última semana del mes (declaraciones, reportes IMSS). Tu RPA tiene que respetarlo: si reintentas agresivo, te marcan IP y te bannean por 24h. Patrón: 3 reintentos con backoff exponencial (30s, 90s, 300s) y si tras eso sigue 503, encolar para el siguiente día.
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=30, min=30, max=300),
retry=retry_if_exception_type((TimeoutError, HTTPError)),
)
async def fetch_repse_status(rfc: str):
return await rpa_session.fetch(rfc)
Un worker FastAPI recibe la solicitud (autenticada por JWT del CRM), encola un job en Redis Queue, un pool de 4 workers Python con undetected-chromedriver corre los flows en contenedores Docker. Cada worker tiene su propio display virtual (Xvfb) porque headed > headless. Pool size limitado por costo de 2captcha (~$0.003 USD por captcha resuelto).
Nunca almacenar credenciales del cliente. Cada sesión de RPA pide login interactivo desde la UI del cliente, las credenciales viven en memoria del worker durante la sesión y se purgan al terminar. Si el cliente quiere "recordame", esa decisión la toma el CFO/CISO del cliente firmando algo, no tu equipo de devs. Hemos visto demandas civiles por esto.
El SAT actualizó sus detecciones en marzo 2025; UC tardó 3 semanas en parchear. Si tu negocio depende de RPA sobre portales gubernamentales, tu plan B siempre debe ser "operador humano con script semi-asistido". Automatizamos lo que no es crítico, dejamos al humano lo que cuesta una multa.
La pregunta del decenio: ¿cuánto falta para que el SAT exponga una API oficial decente y este artículo sea histórico? Spoiler: no en este sexenio.
Artículos relacionados
Migración Mautic → CRM propio sin downtime
Patrón dual-write durante 30 días, backfill batch de 10K contactos por batch, redirect 301 al final. 47K contactos migrados en 6h sin interrumpir capturas.
INEGI BIE/DENUE para context grounding
Inyectar datos reales de INEGI (16M series económicas, 5M empresas geolocalizadas) como context grounding mejora respuestas de LLM sobre mercado mexicano. MCP tool definition y patrón de detection.
Bind ERP como MCP server: el caso SCRAM
Exponer Bind ERP via Model Context Protocol en vez de un wrapper API por cliente. Una capa, varios LLMs (Claude, Cursor, GPT) hablando con el mismo ERP. Rate limits y Redis incluido.