Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
12 KiB
name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params_schema, tested, tests, test_file_path, file_path
| name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | params_schema | tested | tests | test_file_path | file_path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| extract_cmp_tcf | function | py | browser | 1.3.0 | impure | def extract_cmp_tcf(url: str, *, port: int = 9222, wait_load_s: float = 7.0, settle_s: float = 5.0, timeout_s: float = 30.0, accept_first: bool = False, settle_accept_s: float = 4.0, llm_fallback: bool = False) -> dict | Navega por CDP a un Chrome con remote debugging, detecta el CMP (Consent Management Platform: Didomi, OneTrust, Sourcepoint, Quantcast u otro TCF) de un sitio web y lee su objeto IAB TCF v2 para contar vendors (data brokers) y propositos declarados, mas detectar muro pago-o-consientes. Pensado para escanear masivamente periodicos espanoles y cruzar vendor IDs contra la GVL. |
|
|
false | error_go_core |
|
|
false | python/functions/browser/extract_cmp_tcf.py |
Ejemplo
import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from browser.extract_cmp_tcf import extract_cmp_tcf
# Requiere un Chrome lanzado con --remote-debugging-port=9333 (el aislado del MCP).
res = extract_cmp_tcf("https://www.lavanguardia.com", port=9333)
print(res["status"], res["cmp"], res["n_vendors"], res["paywall_consent"])
# -> ok didomi 700 True (recuentos reales varian por sitio/fecha)
Para CMPs que NO exponen vendors pre-consent (Quantcast), aceptar el banner primero:
# bolsamania.com / confilegal.com usan Quantcast: pre-consent dan 0 vendors.
res = extract_cmp_tcf("https://www.bolsamania.com", port=9335, accept_first=True)
print(res["cmp"], len(res["vendor_ids"]), res["accept_method"])
# -> quantcast 1613 sel:.qc-cmp2-summary-buttons button[mode=primary]
Para CMP con clases dinamicas / texto no estandar donde el clic por selectores
sale no-button, activar el fallback LLM (haiku localiza el "aceptar todo"):
# Solo gasta ask_llm si el flujo de selectores fallo de verdad.
res = extract_cmp_tcf("https://www.periodistadigital.com", port=9335,
accept_first=True, llm_fallback=True)
print(res["accept_method"], res.get("llm_used"), len(res["vendor_ids"]))
# -> llm:[data-fnllm="3"] True 812 (si el LLM localizo el control)
# En sitios que ya dieron vendors por selector, llm_used NO aparece.
O directo por CLI: python3 python/functions/browser/extract_cmp_tcf.py "https://www.lavanguardia.com" 9333
(tercer arg 1/accept activa accept_first; cuarto arg 1/llm activa llm_fallback).
Cuando usarla
Cuando necesites auditar de forma masiva que data brokers (vendors IAB TCF) y
propositos declara el banner de cookies de un sitio: escaneo de periodicos, paneles
de prensa, o cualquier corpus de webs con muro de consentimiento. Devuelve un dict
plano listo para volcar a una tabla (DuckDB / Excel) y cruzar vendor_ids contra la
Global Vendor List. Usala como paso de captura dentro de un pipeline de escaneo; los
vendor_ids enriquecidos con la GVL dan el nombre de cada data broker.
Gotchas
- Requiere un Chrome lanzado con
--remote-debugging-port=<port>y al menos una pestana de tipopage. Sin remote debugging, la navegacion falla y devuelve{"status":"error", ...}. NO usar el puerto 9222 si es el navegador personal (tiene sesiones del usuario abiertas): usar 9333, el Chrome aislado del MCP. - Navega la pestana activa (
location.href = url) — reusa el target que elijacdp_eval(primerpage). No abre pestana nueva; si necesitas aislar, abre una pestana dedicada antes. - El CMP puede tardar en inicializar. Si
n_vendorssale 0 ocmpsaleotro_tcfcuando esperabas Didomi, subewait_load_s/settle_s— algunos sitios cargan el SDK del CMP de forma diferida. - El stub
__tcfapi('getTCData', 2, cb)encola el callback hasta que el CMP real carga; por eso hay dos pasadas (arrancar volcado, luego leerwindow.__tcdump). Si el usuario aun no acepto el banner, los recuentos devendor.consentspueden ser 0 perovendor.legitimateInterestsy el recuento de Didomi suelen estar poblados. - Headless puede ser detectado por algunos CMP (cambian comportamiento o no cargan). Para resultados fiables usar un Chrome con UI (el del MCP, 9333).
vendor_idsse obtiene de forma generica para cualquier CMP TCF v2: con Didomi se usan losgetRequiredVendorIds()(lo que el sitio realmente solicita); con cualquier otro CMP (Quantcast, Sourcepoint,otro_tcf) se usa la union de claves detcData.vendor.consents+tcData.vendor.legitimateInterests(los IDs del universo GVL que el CMP tiene configurado). Antes de v1.1.0 solo Didomi rellenabavendor_ids; los demas CMP TCF quedaban con la lista vacia yn_vendors=0.n_vendors=len(vendor_ids)cuando hay lista resuelta; si no, cae a la mejor estimaciondidomi_required>didomi_total_vendors>n_vendor_li.- Si un sitio TCF sigue devolviendo
vendor_idsvacio, casi siempre es porque el CMP inyecta__tcfapide forma muy diferida: subesettle_sa 8-10 en esa llamada. - Quantcast (cmp_id 10) pre-consent devuelve TCData vacio: mientras el banner solo
esta mostrado (
eventStatus:"cmpuishown",tcStringvacio),vendor.consents,vendor.legitimateInterestsyvendor.disclosedVendorsestan TODOS a 0 — no hay forma de leer vendors sin que el usuario interactue con el banner. En cuanto se acepta (o se rechaza) el banner, el TCData se puebla y la funcion extrae cientos/miles de vendor_ids correctamente (verificado: bolsamania.com pasa de 0 a 1613 vendors tras cerrar el banner). Didomi NO sufre esto: exponegetRequiredVendorIds()aunque no haya consentimiento. Para escaneo masivo de sitios Quantcast, pasaraccept_first=True(desde v1.2.0): la funcion acepta el banner por selector/texto antes de leer el TCF. accept_first=Trueclica desde el documento PRINCIPAL: los selectores conocidos (#didomi-notice-agree-button,#onetrust-accept-btn-handler,.qc-cmp2-summary-buttons button[mode=primary],button[aria-label*=Aceptar/Accept]) y el fallback por texto del boton funcionan para Didomi, OneTrust y Quantcast porque renderizan el banner en el DOM de la pagina. Sourcepoint mete el banner dentro de un<iframe>(sp_message_container_*): el clic desde el documento principal NO alcanza el boton dentro del iframe, asi queaccept_methodsaldrano-buttonpara Sourcepoint y los vendors seguiran sin poblarse. No esta resuelto (no hay sitios Sourcepoint en el set actual); resolverlo requeriria evaluar el JS dentro del frame del iframe (otro target CDP). El parametro nunca lanza por esto: simplemente reportano-button.llm_fallback=Truegasta una llamada aask_llm(haiku) por cada sitio que lo dispare (rate limits de la API Anthropic). El fallback solo se invoca cuando el flujo normal de selectores fallo de verdad (vendor_idsvacio tras leer el TCData): los sitios cuyo CMP estandar (Didomi/OneTrust/Quantcast por selector o texto) ya recupera vendors NO gastan la llamada. Caso clave: Didomi exponegetRequiredVendorIds()sin necesidad de consentir, asi que aunque el clic salgano-buttonelvendor_idsya viene poblado y el LLM no se dispara. Para un escaneo masivo esto acota el gasto a los CMP con clases dinamicas / texto no estandar. El fallback marcaaccept_method='llm:<selector>'(clic LLM exitoso), o'llm:no-control'si el LLM no encontro un boton aceptable / el clic fallo, y siempre anadellm_used:True+llm_reason. NO resuelve banners dentro de iframes (Sourcepoint): el LLM recolecta controles del documento principal, igual que el flujo de selectores.- Nunca lanza: cualquier error de red, CDP o parseo JSON se reporta en
errorconstatus="error".
Capability growth log
- v1.3.0 (2026-06-18) — llm_fallback: si el clic por selectores falla (no-button), usa find_consent_controls_llm (haiku) para localizar y clicar 'aceptar todo' antes de leer el TCF. Gotcha: el fallback gasta una llamada a ask_llm (rate limits) por sitio que lo necesite.
- v1.2.0 (2026-06-18) — accept_first: acepta el banner (Didomi/OneTrust/Quantcast por selector + fallback por texto) antes de leer el TCF, para CMPs que no exponen vendors pre-consent (Quantcast). Gotcha: Sourcepoint mete el banner en un iframe, el clic desde el documento principal no lo alcanza (sale 'no-button').
- v1.1.0 (2026-06-18) — vendor_ids genericos desde tcData.vendor.consents/legitimateInterests para CMPs no-Didomi (Quantcast, otro_tcf); +settle para CMPs lentos.