capture-site
Guarda todo lo que sirve el sitio en vivo, una vez, para que cada paso posterior funcione a partir de la captura.
La regla de oro
El sitio en vivo es de solo lectura, y la captura es de solo lectura después. Los scripts solo realizan solicitudes GET y HEAD con ritmo pausado; nunca envían un formulario, inician sesión ni obtienen manualmente algo para llenar un vacío. Una vez escritas las notas, nada bajo capture/ se edita: es la evidencia que lee cada puerta.
Cuándo usarlo
Paso 2 de una conversión (convert-site lo ejecuta), o en cualquier momento en que se deba inventariar un sitio en vivo (un sitio de staging o nuevo es trabajo de launch-audit). Una captura que salió con código 3 se reanuda, como se indica a continuación.
Ritmo
Cada script envía un agente de usuario de Chrome de escritorio. Los scripts de captura (capture, media, assets, fingerprint) comparten un limitador por host: por defecto, los inicios de solicitud están separados por 400 ms con hasta 4 en vuelo (media: 6), por lo que un host que responde rápidamente se lee en minutos. Los pasos de Chromium (shoot, css-coverage, styles) cargan una página a la vez, con 500 ms de separación, y launch-audit y pre-launch mantienen su propio ritmo. El limitador se adapta automáticamente:
- un 429 o 503 duplica el retraso de ese host (hasta 32 veces) y lo reduce a una solicitud a la vez; después de cada 30 s de respuestas limpias, recupera un paso (mitad del retraso, una más en vuelo) hasta volver a los valores predeterminados;
- una respuesta que tarda más de 5 s reduce a la mitad las solicitudes en vuelo en ese host (sin repetir mientras esté reducido a la mitad), y se recupera de la misma manera, una más en vuelo por cada 30 s de respuestas limpias;
- un 403 o un error de red cuenta para la parada de 3 seguidos a continuación, como antes.
--polite es el ritmo anterior: una solicitud a la vez, con 2500 ms de separación (capture, media, assets). Úsalo desde el principio en un hosting compartido con un muro antirrobots (el /.well-known/sgcaptcha/ de SiteGround, hosts que responden 429 o 503 a unas pocas solicitudes rápidas), o cuando una ejecución se detuvo por bloqueos: reanuda con --polite. --delay <ms> y --concurrency <n> anulan los valores predeterminados o --polite. Mantén los valores predeterminados o --polite contra un sitio en vivo (--delay 0 es solo para datos locales de prueba), y nunca cambies --ua para evitar un bloqueo.
captureobtiene hasta--concurrencyURLs en cola por adelantado y las registra en el orden de la cola, por lo que la captura es igual que un rastreo de uno en uno. Intenta cada URL 3 veces. Una URL aún bloqueada después de eso (403, 429, 503 o un error de red) se registra con su estado yattemptseninventory.json(un sitemap o lista REST enmeta.jsondiscoveryErrors) y el rastreo continúa. Se detiene solo después de que 3 URLs diferentes seguidas hayan agotado sus intentos sin éxito entre ellas, estado guardado, esas tres puestas en cola nuevamente con nuevos intentos. Nunca solicitawp-admin,wp-login,xmlrpc.phpo búsquedas?s=.mediaintenta cada archivo 3 veces: un 429 o 503 persistente lo detiene de inmediato; un 403 o error de red se registra como el estado de ese archivo, y 3 archivos de este tipo seguidos (en el orden en que llegan las respuestas) lo detienen. Los archivos que se están descargando cuando se detiene se dejan terminar. Guardamedia.jsoncada 100 archivos, por lo que una ejecución que se interrumpe se reanuda cerca de donde estaba.fingerprintno reintenta: una página de inicio bloqueada, o una que es un desafío antirrobots, es salida 3.assetsyshootretroceden y se detienen después de 3 respuestas bloqueadas seguidas.
La secuencia de comandos
Ejecutar desde la carpeta que contendrá capture/ (la raíz del repositorio del sitio). <skill-dir> es la ruta absoluta de la carpeta de esta habilidad, en una copia del kit donde se ha ejecutado npm install (los scripts importan sus paquetes). Cada script imprime --help; ejecútalo en lugar de leer el código fuente. Ejecuta cada paso como su propio comando, en este orden:
-
Fingerprint (huella digital), luego lee la referencia de la plataforma para lo que nombra (tabla a continuación):
node <skill-dir>/scripts/fingerprint.mjs https://www.example.com -
Captura. El descubrimiento son los sitemaps (cada línea
Sitemap:en robots.txt, más el índice predeterminado de la plataforma), las listas REST (WordPress, cuando la huella encuentra REST;--no-restomite), el rastreo de enlaces, y--seed <path>o--seed-file <file>(una ruta o URL por línea, comentarios#) para rutas que el rastreo no puede alcanzar (URL antiguas, un.htaccessantiguo). Después del rastreo, las rutas de Wayback que no encontró van awayback-unverified.txt(--no-waybackomite; un listado que falla se solicita una vez más 10 s después antes de quemeta.jsonwaybackregistrefailed). Los enlaces cortos?p=se registran sin verificar y nunca se obtienen a menos que pases--verify-shortlinks. Después del rastreo, solicita una ruta que no puede existir (/<32 hex>/) una vez, por lo que la página 404 del sitio se guarda comopages/404.html(meta.jsonnotFound; un sitio que responde 200 o redirige allí se registra sin página), y solicita/favicon.icoy/apple-touch-icon.pnguna vez cada uno, siguiendo redirecciones (meta.jsonicons: ruta a{ status, file, contentType, bytes }); uno que responde 200 se guarda byte por byte comoassets/root-favicon.icooassets/root-apple-touch-icon.png(una respuesta HTML no se guarda y tiene unnote; uno de más de 5 MB es estado"too-large"), yassets.mjslo enumera enassets/index.jsoncomo tipo"root-icon"con supath, por lo que la compilación lo envía allí. Las URLs se codifican con escapes de porcentaje en mayúsculas (%c3%a9y%C3%A9son una URL), por lo que una página enlazada con ambas ortografías se captura una vez. Un sitemap que robots.txt nombra y que responde 404 (o cualquier no 200) se enumera ensitemaps/index.jsoncon su estado y enmeta.jsondiscoveryErrors. Un sitemap en otro host (robots.txt que nombra uno de un sitio hermano, o un índice que enumera uno; www y dominio raíz cuentan como un host) se enumera allí como{ url, host, skipped: "other host" }y nunca se obtiene, por lo que ninguna de sus URLs ingresa al rastreo. Dos URLs de sitemap con el mismo nombre de archivo nunca se sobrescriben entre sí: el segundo se guarda con un sufijo de su ruta de directorio (page-sitemap-es.xml).--exclude <prefix>[,<prefix>...]deja partes del host fuera (los subsitios de un WordPress multisitio como/president/, o una sección que el propietario mantiene): una URL cuya ruta comienza con uno nunca se solicita, ya sea que un sitemap, las listas REST, un enlace o una redirección conduzcan allí. Un sitemap bajo uno se enumera ensitemaps/index.jsoncomo{ url, skipped: "excluded" }; una redirección hacia uno se registra con ese destino, sin solicitar; los enlaces a uno permanecen en el HTML guardado y se enumeran enlinks.jsonexcluded, nointernal;meta.jsonexcludednombra los prefijos y la línea base los incluye. Los prefijos y rutas se comparan en una forma, por lo que/présidence/,/pr%c3%a9sidence/y/pr%C3%A9sidence/son el mismo prefijo. Una hoja de estilo o icono raíz que redirige bajo uno no se sigue allí (la hoja se enumera con estado"excluded").--resumelos mantiene; un prefijo agregado en--resumeelimina lo que ya se capturó bajo él (sus páginas con sus archivospages/ytext/, redirecciones de él, feeds y sitemaps bajo él, y hojas de estilo y scripts que solo esas páginas usaron) e imprime lo que eliminó.media.mjsyassets.mjstambién omiten archivos bajo ellos.node <skill-dir>/scripts/capture.mjs https://www.example.com --out captureLuego, la segunda pasada de Wayback, cuando
wayback-unverified.txtno está vacío: solicita cada ruta archivada una vez, por lo que las que aún redirigen terminan encapture/redirects.jsoncon fuenteseed(las redirecciones de la línea base las recogen) y el resto se registra con su estado eninventory.json.--seed,--seed-filey--include-queryse aplican todos en--resume, y no se vuelve a preguntar a Wayback Machine:node <skill-dir>/scripts/capture.mjs https://www.example.com --out capture --resume --seed-file capture/wayback-unverified.txt -
Medios. Enumera cada archivo multimedia en
capture/media.jsony lo guarda en.conversion/media-cache/, el directorio de trabajo de la conversión, que permanece fuera de git:node <skill-dir>/scripts/media.mjs --capture capture --download .conversion/media-cacheDescarga seis archivos a la vez. Por defecto (
--sizes referenced) obtiene los originales y cada tamaño que usa el sitio: aquel al que apuntan una página, hoja de estilo, srcset, etiqueta og o sitemap, o cuyo nombre de archivo aparece en cualquier parte de las páginas, hojas de estilo o scripts capturados (data-thumb, data-bg, configuraciones JSON, scripts de slider). Un tamaño de WordPress que solo nombra la lista de medios REST se enumera condownloaded: false, reason: "unreferenced size"y no se solicita. Imprime el desglose, p. ej.,920 originals + referenced sizes (downloaded), 4,520 unreferenced sizes (listed only): repite esa línea a la persona. Usa--sizes allcuando el propietario dice que correos electrónicos antiguos u otros sitios pueden enlazar a esos tamaños.Los hosts que cambian el tamaño mediante una cadena de consulta (WordPress VIP, Jetpack Photon:
photo.jpg?w=1024,?resize=300,200) sirven todos los tamaños en la misma ruta. El original es la ruta desnuda, por lo que eso es lo que se solicita y guarda; cada cadena de consulta vista se enumera bajovariants(no solicitada;--sizes alllos guarda como<path>%3F<query>bajo una carpeta hermana,.conversion/media-cache-variants/, por lo que la caché de medios que se carga o copia en el repositorio contiene solo rutas desnudas). Cuando la ruta desnuda responde con un error (4xx o 5xx; una redirección se registra con su ubicación, y un archivo demasiado grande se solicita nuevamente una vez que se aumenta el límite), se guarda una variante en su lugar y la entradadownloadedFromes la URL de la que proviene. Una consulta de invalidación de caché (sin parámetrow,h,resize,crop,fit,quality,formatos, p. ej.,?ver=3) es el mismo archivo, por lo que se prefiere y no se marca nada más; de lo contrario, se guarda la variante más ancha y la entrada también diceresized: true. La ejecución imprime una línea por archivo y un recuento (2 originals unavailable (resized: true) ...), baseline/media.json mantiene ambos campos, y la puerta de medios repite el recuento comoN resized (original unavailable on live)sin fallar, ya que compara con los bytes realmente guardados. Repite ese recuento a la persona y enumera esos archivos en el plan y el runbook como originales que el sitio en vivo ya no sirve. -
Plantillas. Agrupa las páginas que respondieron 200 en
capture/templates.json. En WordPress, las páginas se agrupan primero por clase de cuerpo de plantilla (home,page,single-post,archive, clases de plantilla) y una página cuyo marcado es claramente diferente (Jaccard por debajo de 0.5) se separa comopage-2; otras plataformas se fusionan por marcado en Jaccard 0.6, comotemplate-<n>:node <skill-dir>/scripts/templates.mjs --capture capture -
Activos. Logotipo, favicon, apple-touch-icon, el manifiesto web
<link rel=manifest>y cada fuente@font-faceencapture/assets/, más el/favicon.icoy/apple-touch-icon.pngraíz (root-favicon.*,root-apple-touch-icon.*) cuandometa.jsoniconslos registró en 200:node <skill-dir>/scripts/assets.mjs --capture captureEl logotipo se busca en la página de inicio dentro de
<header>primero, luego dentro de cualquier otro elemento cuya clase o id nombre un logotipo (.logo,.site-logo,#logo-wrap). En cada uno: un<img>cuyo src, alt, class o id tenga la palabra "logo" (no "logout"), luego un<svg>en línea con "logo" en su clase, id, aria-label o<title>(guardado comologo.svg,url: nullenassets/index.json; su nota lo dice cuando solo<use>un símbolo definido en otra parte de la página, que se renderiza vacío por sí solo), luego la primera<img>en un enlace a la página de inicio, luego la primera<img>. Verificaassets/logo.*visualmente: un avatar de cuenta o una marca de patrocinador aún puede ganar en un encabezado inusual. El favicon y apple-touch-icon se guardan tal como se sirven desde su href<link>, incluida la cadena de consulta, por lo que uno que apunta a un cambio de tamaño (?w=32,?w=180) de un archivo de uploads difiere en bytes de la entrada de ese archivo enmedia.json: mantén el icono guardado, no el original. -
Capturas de pantalla en vivo, una por plantilla a 390, 768 y 1440, con el shooter de revisión visual:
node <skill-dir>/../visual-review/scripts/shoot.mjs --base https://www.example.com --routes capture/templates.json --widths 390,768,1440 --out capture/screens/live -
Lighthouse (opcional). Solo cuando
npx --no-install lighthouse --versionresponda; nunca lo instales sin preguntar; si falta, dila en las notas (un salto, no un pase). Ejecutamkdir -p capture/lighthouse-live, luego una ejecución por cadarepresentativeentemplates.json, por turno:npx --no-install lighthouse https://www.example.com/ --quiet --chrome-flags="--headless=new" --output json --output html --output-path capture/lighthouse-live/home -
README. Resume la captura en
capture/README.md; su## Notescomienza con líneas generadas, reescritas en cada ejecución (cuántas rutas de Wayback verificó la segunda pasada y qué respondió cada una: estado, destino de redirección; un listado de Wayback que falló o fue rechazado por tamaño; cada URL que aún falla después de sus reintentos). Ejecútalo al final, y después de cualquier re-ejecución:node <skill-dir>/scripts/readme.mjs --capture capture
| Script | Salida |
|---|---|
fingerprint | 0 terminado, 2 uso o inalcanzable, 3 bloqueo o desafío antirrobots |
capture | 0 terminado, 2 uso, 3 detenido por bloqueos, inalcanzable, desafío antirrobots (todo reanudable), o ninguna página respondió 200 |
media | 0 terminado (archivos faltantes incluidos), 2 uso, sin captura o sin página que respondiera 200, 3 detenido por bloqueos |
assets | 0 terminado (archivos faltantes incluidos), 2 uso o sin captura, 3 detenido por bloqueos |
templates | 0 terminado, 2 uso, sin inventory.json, o "sin páginas capturadas" (ninguna respondió 200) |
readme | 0 terminado, 2 uso o sin inventory.json |
shoot | 0 todas disparadas, 1 una ruta falló, 2 uso, 3 detenido por bloqueos |
En caso de salida 3
El sitio está bloqueando solicitudes o no se puede acceder a él. Espera (minutos, no segundos), luego:
fingerprint: ejecútalo de nuevo.capture: ejecuta el mismo comando con--resume. Las URLs aún en cola se reintentan
…
[truncado para traducción]