capture-site
Enregistrez tout ce que le site en direct sert, une fois, pour que chaque étape ultérieure fonctionne à partir de la capture.
La règle d'or
Le site en direct est en lecture seule et la capture est en lecture seule par la suite. Les scripts effectuent uniquement des requêtes GET et HEAD espacées ; ne soumettez jamais de formulaire, ne vous connectez pas et ne récupérez rien manuellement pour combler une lacune. Une fois les notes écrites, rien sous capture/ n'est modifié : c'est la preuve que chaque porte lit.
Quand l'utiliser
Étape 2 d'une conversion (convert-site l'exécute), ou à tout moment où un site en direct doit être inventorié (un site de staging ou nouveau est le travail de launch-audit). Une capture qui s'est terminée avec le code 3 reprend comme ci-dessous.
Rythme
Chaque script envoie un agent utilisateur Chrome de bureau. Les scripts de capture (capture, media, assets, fingerprint) partagent un limiteur par hôte : par défaut, les démarrages de requêtes sont espacés de 400 ms avec jusqu'à 4 en vol (media : 6), donc un hôte qui répond rapidement est lu en quelques minutes. Les étapes Chromium (shoot, css-coverage, styles) chargent une page à la fois, espacées de 500 ms, et launch-audit et pre-launch conservent leur propre rythme. Le limiteur s'adapte tout seul :
- un 429 ou 503 double le délai de cet hôte (jusqu'à 32 fois) et le réduit à une requête à la fois ; après 30 s de réponses propres, il récupère un cran (la moitié du délai, un de plus en vol) jusqu'à revenir aux valeurs par défaut ;
- une réponse qui prend plus de 5 s réduit de moitié les requêtes en vol sur cet hôte (pas de nouveau tant qu'elles sont réduites), et il récupère de la même manière, une de plus en vol par 30 s de réponses propres ;
- un 403 ou une erreur réseau compte pour l'arrêt de 3 consécutifs ci-dessous, comme avant.
--polite est l'ancien rythme : une requête à la fois, espacées de 2500 ms (capture, media, assets). Utilisez-le dès le départ sur un hébergement partagé avec un mur anti-bot (le /.well-known/sgcaptcha/ de SiteGround, les hôtes qui répondent 429 ou 503 à quelques requêtes rapides), ou lorsqu'une exécution s'est arrêtée sur des blocages : reprenez avec --polite. --delay <ms> et --concurrency <n> remplacent les valeurs par défaut ou --polite. Gardez les valeurs par défaut ou --polite contre un site en direct (--delay 0 est réservé aux fixtures locales), et ne changez jamais --ua pour contourner un blocage.
-
capturerécupère jusqu'à--concurrencyURL mises en file d'attente à l'avance et les enregistre dans l'ordre de la file, de sorte que la capture est identique à une exploration une par une. Il essaie chaque URL 3 fois. Une URL toujours bloquée après cela (403, 429, 503 ou une erreur réseau) est enregistrée avec son statut etattemptsdansinventory.json(une liste de sitemap ou REST dansmeta.jsondiscoveryErrors) et l'exploration continue. Il s'arrête seulement après que 3 URL différentes d'affilée aient épuisé leurs tentatives sans succès entre elles, l'état sauvegardé, ces trois remises en file avec de nouvelles tentatives. Il ne demande jamaiswp-admin,wp-login,xmlrpc.phpou les recherches?s=. -
mediaessaie chaque fichier 3 fois : un 429 ou 503 persistant l'arrête immédiatement ; une erreur 403 ou réseau est enregistrée comme statut de ce fichier, et 3 fichiers consécutifs (dans l'ordre d'arrivée des réponses) l'arrêtent. Les fichiers en cours de téléchargement lorsqu'il s'arrête sont laissés se terminer. Il sauvegardemedia.jsontous les 100 fichiers, de sorte qu'une exécution interrompue reprend près de là où elle était. -
fingerprintne réessaie pas : une page d'accueil bloquée, ou qui est un défi bot, provoque la sortie de code 3.assetsetshootreculent et s'arrêtent après 3 réponses bloquées consécutives.
La séquence de commandes
Exécuter depuis le dossier qui contiendra capture/ (la racine du dépôt du site). <skill-dir> est le chemin absolu du dossier de ce skill, dans une copie du kit où npm install a été exécuté (les scripts importent ses paquets). Chaque script affiche --help ; exécutez-le plutôt que de lire la source. Exécutez chaque étape comme sa propre commande, dans cet ordre :
-
Fingerprint, puis lisez la référence de la plateforme pour ce qu'il nomme (tableau ci-dessous) :
node <skill-dir>/scripts/fingerprint.mjs https://www.example.com -
Capture. La découverte comprend les sitemaps (chaque ligne
Sitemap:dans robots.txt, plus l'index par défaut de la plateforme), les listes REST (WordPress, lorsque l'empreinte trouve REST ;--no-restsaute), l'exploration des liens, et--seed <path>ou--seed-file <file>(un chemin ou URL par ligne, commentaires#) pour les chemins que l'exploration ne peut pas atteindre (anciennes URL, ancien.htaccess). Après l'exploration, les chemins Wayback introuvables vont danswayback-unverified.txt(--no-waybacksaute ; une liste qui échoue est demandée une fois de plus 10 s plus tard avant quemeta.jsonwaybackn'enregistrefailed). Les shortlinks?p=sont enregistrés non vérifiés et jamais récupérés à moins de passer--verify-shortlinks. Après l'exploration, il demande une fois un chemin qui ne peut pas exister (/<32 hex>/), de sorte que la page 404 du site est enregistrée commepages/404.html(meta.jsonnotFound; un site qui répond 200 ou redirige y est enregistré sans page), et demande/favicon.icoet/apple-touch-icon.pngune fois chacun, les redirections suivies (meta.jsonicons: chemin vers{ status, file, contentType, bytes }; une réponse 200 est enregistrée octet par octet commeassets/root-favicon.icoouassets/root-apple-touch-icon.png(une réponse HTML n'est pas enregistrée et a unenote; un fichier de plus de 5 Mo a le statut"too-large"), etassets.mjsle liste dansassets/index.jsoncomme type"root-icon"avec sonpath, pour que la construction l'y envoie. Les URL sont indexées avec des échappements de pourcentage en majuscules (%c3%a9et%C3%A9sont une seule URL), de sorte qu'une page liée avec les deux orthographes est capturée une fois. Un sitemap nommé par robots.txt qui répond 404 (ou tout non-200) est listé danssitemaps/index.jsonavec son statut et dansmeta.jsondiscoveryErrors. Un sitemap sur un autre hôte (robots.txt nommant celui d'un site sœur, ou un index en listant un ; www et apex comptent comme un seul hôte) y est listé comme{ url, host, skipped : "other host" }et jamais récupéré, de sorte qu'aucune de ses URL n'entre dans l'exploration. Deux URL de sitemap avec le même nom de fichier ne se remplacent jamais l'une l'autre : la seconde est enregistrée avec un suffixe de son chemin de répertoire (page-sitemap-es.xml).--exclude <prefix>[,<prefix>...]laisse de côté des parties de l'hôte (les sous-sites d'un WordPress multisite comme/president/, ou une section que le propriétaire conserve) : une URL dont le chemin commence par l'un d'eux n'est jamais demandée, qu'un sitemap, les listes REST, un lien ou une redirection y mène. Un sitemap sous l'un d'eux est listé danssitemaps/index.jsoncomme{ url, skipped : "excluded" }; une redirection vers l'un d'eux est enregistrée avec cette cible, non demandée ; les liens vers l'un d'eux restent dans le HTML sauvegardé et sont listés danslinks.jsonexcluded, pasinternal;meta.jsonexcludednomme les préfixes et la base de référence les porte. Les préfixes et chemins sont comparés sous une seule forme, donc/présidence/,/pr%c3%a9sidence/et/pr%C3%A9sidence/sont le même préfixe. Une feuille de style ou icône racine qui redirige sous l'un d'eux n'est pas suivie là (la feuille est listée avec le statut"excluded").--resumeles conserve ; un préfixe ajouté sur--resumesupprime ce qui a déjà été capturé en dessous (ses pages avec leurs fichierspages/ettext/, les redirections qui en proviennent, les flux et sitemaps en dessous, et les feuilles de style et scripts que seules ces pages utilisaient) et affiche ce qui a été supprimé.media.mjsetassets.mjsignorent également les fichiers en dessous.node <skill-dir>/scripts/capture.mjs https://www.example.com --out capturePuis le second passage Wayback, lorsque
wayback-unverified.txtn'est pas vide : il demande chaque chemin archivé une fois, de sorte que ceux qui redirigent encore atterrissent danscapture/redirects.jsonavec la sourceseed(les redirections de la base de référence les récupèrent) et le reste sont enregistrés avec leur statut dansinventory.json.--seed,--seed-fileet--include-querys'appliquent tous sur--resume, et la Wayback Machine n'est pas sollicitée à nouveau :node <skill-dir>/scripts/capture.mjs https://www.example.com --out capture --resume --seed-file capture/wayback-unverified.txt -
Médias. Liste chaque fichier média dans
capture/media.jsonet le sauvegarde sous.conversion/media-cache/, le répertoire de travail de la conversion, qui reste hors de git :node <skill-dir>/scripts/media.mjs --capture capture --download .conversion/media-cacheIl télécharge six fichiers à la fois. Par défaut (
--sizes referenced), il récupère les originaux et toutes les tailles que le site utilise : celles vers lesquelles pointent une page, une feuille de style, un srcset, une balise og ou un sitemap, ou dont le nom de fichier apparaît n'importe où dans les pages, feuilles de style ou scripts capturés (data-thumb, data-bg, paramètres JSON, scripts de slider). Une taille WordPress que seule la liste média REST nomme est listée avecdownloaded : false, reason : "unreferenced size"et n'est pas demandée. Il affiche la répartition, par ex.920 originals + referenced sizes (downloaded), 4,520 unreferenced sizes (listed only): répétez cette ligne à la personne. Utilisez--sizes alllorsque le propriétaire dit que d'anciens e-mails ou d'autres sites peuvent lier à ces tailles.Les hôtes qui redimensionnent par chaîne de requête (WordPress VIP, Jetpack Photon :
photo.jpg?w=1024,?resize=300,200) servent toutes les tailles au même chemin. L'original est le chemin nu, donc c'est ce qui est demandé et sauvegardé ; chaque chaîne de requête vue est listée sousvariants(non demandée ;--sizes allles sauvegarde sous forme de<path>%3F<query>dans un dossier frère,.conversion/media-cache-variants/, de sorte que le cache média qui est téléchargé ou copié dans le dépôt ne contient que les chemins nus). Lorsque le chemin nu répond par une erreur (4xx ou 5xx ; une redirection est enregistrée avec son emplacement, et un fichier trop volumineux est redemandé une fois le plafond relevé), une variante est sauvegardée à sa place et l'entréedownloadedFromest l'URL d'où elle provient. Une requête de vidage de cache (sans paramètrew,h,resize,crop,fit,quality,formatous, par exemple?ver=3) est le même fichier, donc elle est préférée et rien d'autre n'est marqué ; sinon, la variante la plus large est sauvegardée et l'entrée indique égalementresized : true. L'exécution affiche une ligne par fichier et un décompte (2 originals unavailable (resized : true) ...), baseline/media.json conserve les deux champs, et la porte média répète le décompte commeN resized (original unavailable on live)sans échouer, puisqu'elle compare les octets réellement sauvegardés. Répétez ce décompte à la personne et listez ces fichiers dans le plan et le runbook comme des originaux que le site en direct ne sert plus. -
Modèles. Regroupe les pages qui ont répondu 200 dans
capture/templates.json. Sur WordPress, les pages se regroupent d'abord par classe de corps de modèle (home,page,single-post,archive, classes de modèle) et une page dont le balisage est clairement différent (Jaccard inférieur à 0,5) se sépare enpage-2; les autres plates-formes fusionnent par balisage à Jaccard 0,6, en tant quetemplate-<n>:node <skill-dir>/scripts/templates.mjs --capture capture -
Actifs. Logo, favicon, apple-touch-icon, le manifeste web
<link rel=manifest>et chaque police@font-facedanscapture/assets/, plus le/favicon.icoracine et/apple-touch-icon.png(root-favicon.*,root-apple-touch-icon.*) lorsquemeta.jsoniconsles a enregistrés à 200 :node <skill-dir>/scripts/assets.mjs --capture captureLe logo est recherché sur la page d'accueil à l'intérieur du
<header>d'abord, puis à l'intérieur de tout autre élément dont la classe ou l'id nomme un logo (.logo,.site-logo,#logo-wrap). Dans chacun : une<img>dont le src, alt, class ou id contient le mot "logo" (pas "logout"), puis un<svg>en ligne avec "logo" dans sa class, id , aria-label ou<title>(sauvegardé souslogo.svg,url : nulldansassets/index.json; sa note l'indique lorsqu'il<use>uniquement un symbole défini ailleurs sur la page, qui s'affiche vide tout seul), puis la première<img>dans un lien vers la page d'accueil, puis la première<img>. Vérifiezassets/logo.*à l'œil : un avatar de compte ou une marque de sponsor peut encore gagner sur un en-tête inhabituel. Le favicon et l'apple-touch-icon sont sauvegardés tels que servis depuis leur href<link>, chaîne de requête incluse, de sorte que celui qui pointe vers un redimensionnement (?w=32,?w=180) d'un fichier téléchargé diffère en octets de l'entrée de ce fichier dansmedia.json: conservez l'icône sauvegardée, pas l'original. -
Captures d'écran en direct, une par modèle à 390, 768 et 1440, avec le tireur de révision visuelle :
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 (optionnel). Seulement lorsque
npx --no-install lighthouse --versionrépond ; ne l'installez jamais sans demande ; s'il manque, dites-le dans les notes (un saut, pas un succès). Exécutezmkdir -p capture/lighthouse-live, puis une exécution parrepresentativedanstemplates.json, à tour de rôle :npx --no-install lighthouse https://www.example.com/ --quiet --chrome-flags="--headless=new" --output json --output html --output-path capture/lighthouse-live/home -
README. Résume la capture dans
capture/README.md; son## Notess'ouvre avec des lignes générées, réécrites à chaque exécution (combien de chemins Wayback le second passage a vérifiés et ce que chacun a répondu : statut, cible de redirection ; une liste Wayback qui a échoué ou a été refusée pour taille ; chaque URL qui échoue toujours après ses tentatives). Exécutez-le en dernier, et après toute réexécution :node <skill-dir>/scripts/readme.mjs --capture capture
| Script | Sortie |
|---|---|
fingerprint | 0 terminé, 2 utilisation ou inaccessible, 3 blocage ou défi bot |
capture | 0 terminé, 2 utilisation, 3 arrêté sur blocages, inaccessible, défi bot (tout reprenable), ou aucune page n'a répondu 200 |
media | 0 terminé (fichiers manquants inclus), 2 utilisation, pas de capture ou aucune page ayant répondu 200, 3 arrêté sur blocages |
assets | 0 terminé (fichiers manquants inclus), 2 utilisation ou pas de capture, 3 arrêté sur blocages |
templates | 0 terminé, 2 utilisation, pas de inventory.json, ou "aucune page capturée" (aucune n'a répondu 200) |
readme | 0 terminé, 2 utilisation ou pas de inventory.json |
shoot | 0 toutes prises, 1 une route a échoué, 2 utilisation, 3 arrêté sur blocages |
Sur sortie 3
Le site bloque les requêtes ou est inaccessible. Attendez (minutes, pas secondes), puis :
fingerprint: exécutez-le à nouveau.capture: exécutez la même commande avec--resume. Les URL encore en file d'attente sont réessayées.