capture-site
Salve tudo que o site ao vivo serve, uma vez, para que cada etapa posterior funcione a partir da captura.
A regra de ouro
O site ao vivo é somente leitura, e a captura é somente leitura depois. Os scripts apenas fazem requisições GET e HEAD ritmadas; nunca enviam um formulário, fazem login ou buscam manualmente para preencher uma lacuna. Depois que as notas são escritas, nada em capture/ é editado: é a evidência que cada verificação lê.
Quando usar
Etapa 2 de uma conversão (convert-site a executa), ou sempre que um site ao vivo precisa ser inventariado (um site de staging ou novo é tarefa do launch-audit). Uma captura que saiu com código 3 é retomada, conforme abaixo.
Ritmo
Cada script envia um user agent do Chrome desktop. Os scripts de captura (capture, media, assets, fingerprint) compartilham um limitador por host: por padrão, os inícios de requisição são espaçados em 400 ms com até 4 voos simultâneos (media: 6), para que um host que responde rapidamente seja lido em minutos. As etapas do Chromium (shoot, css-coverage, styles) carregam uma página por vez, com 500 ms de intervalo, e launch-audit e pre-launch mantêm seu próprio ritmo. O limitador se adapta automaticamente:
- um 429 ou 503 dobra o atraso desse host (até 32 vezes) e reduz para uma requisição por vez; após cada 30 s de respostas limpas, ele recupera um passo (metade do atraso, mais um voo) até voltar aos padrões;
- uma resposta que leva mais de 5 s reduz pela metade os voos simultâneos nesse host (não novamente enquanto reduzido), e ele se recupera da mesma forma, um voo a mais a cada 30 s de respostas limpas;
- um 403 ou erro de rede conta para a parada de 3 consecutivos abaixo, como antes.
--polite é o ritmo antigo: uma requisição por vez, com 2500 ms de intervalo (capture, media, assets). Use-o desde o início em hospedagem compartilhada com uma barreira de bot (o /.well-known/sgcaptcha/ do SiteGround, hosts que respondem 429 ou 503 a algumas requisições rápidas), ou quando uma execução parou em bloqueios: retome com --polite. --delay <ms> e --concurrency <n> substituem os padrões ou --polite. Mantenha os padrões ou --polite contra um site ao vivo (--delay 0 é apenas para fixtures locais), e nunca mude --ua para contornar um bloqueio.
capturebusca até--concurrencyURLs da fila adiantadas e as registra na ordem da fila, para que a captura seja igual a um rastreamento um-a-um. Ele tenta cada URL 3 vezes. Uma URL ainda bloqueada após isso (403, 429, 503 ou erro de rede) é registrada com seu status eattemptseminventory.json(uma lista de sitemap ou REST emmeta.jsondiscoveryErrors) e o rastreamento continua. Ele para apenas depois que 3 URLs diferentes em sequência esgotaram suas tentativas sem sucesso entre elas, com estado salvo, essas três enfileiradas novamente com novas tentativas. Ele nunca requisitawp-admin,wp-login,xmlrpc.phpou buscas?s=.mediatenta cada arquivo 3 vezes: um 429 ou 503 persistente o interrompe imediatamente; um 403 ou erro de rede é registrado como status desse arquivo, e 3 desses arquivos em sequência (na ordem em que as respostas chegam) o interrompem. Arquivos já sendo baixados quando ele para são deixados terminar. Ele salvamedia.jsona cada 100 arquivos, para que uma execução interrompida retome perto de onde parou.fingerprintnão tenta novamente: uma página inicial bloqueada, ou que seja um desafio de bot, resulta em saída 3.assetseshootrecuam e param após 3 respostas bloqueadas consecutivas.
A sequência de comandos
Execute a partir da pasta que conterá capture/ (a raiz do repositório do site). <skill-dir> é o caminho absoluto da pasta desta skill, em uma cópia do kit onde npm install foi executado (os scripts importam seus pacotes). Cada script imprime --help; execute-o em vez de ler o código-fonte. Execute cada etapa como seu próprio comando, nesta ordem:
-
Fingerprint, então leia a referência da plataforma para o que ele nomeia (tabela abaixo):
node <skill-dir>/scripts/fingerprint.mjs https://www.example.com -
Capture. A descoberta são os sitemaps (cada linha
Sitemap:em robots.txt, mais o índice padrão da plataforma), as listas REST (WordPress, quando o fingerprint encontra REST;--no-restpula), o rastreamento de links, e--seed <path>ou--seed-file <file>(um caminho ou URL por linha, comentários#) para caminhos que o rastreamento não alcança (URLs antigas, um.htaccessantigo). Após o rastreamento, caminhos do Wayback que ele não encontrou vão parawayback-unverified.txt(--no-waybackpula; uma listagem que falha é solicitada novamente 10 s depois antes demeta.jsonwaybackregistrarfailed). Shortlinks?p=são registrados não verificados e nunca buscados, a menos que você passe--verify-shortlinks. Após o rastreamento, ele solicita um caminho que não pode existir (/<32 hex>/) uma vez, para que a página 404 do próprio site seja salva comopages/404.html(meta.jsonnotFound; um site que responde 200 ou redireciona para lá é registrado sem página), e solicita/favicon.icoe/apple-touch-icon.pnguma vez cada, redirecionamentos seguidos (meta.jsonicons: caminho para{ status, file, contentType, bytes }); um que responde 200 é salvo byte a byte comoassets/root-favicon.icoouassets/root-apple-touch-icon.png(uma resposta HTML não é salva e tem umanote; um com mais de 5 MB tem status"too-large"), eassets.mjso lista emassets/index.jsoncomo tipo"root-icon"com seupath, para que a construção o envie para lá. URLs são indexadas com escapes percentuais maiúsculos (%c3%a9e%C3%A9são uma URL), para que uma página vinculada com ambas as grafias seja capturada uma vez. Um sitemap que robots.txt nomeia e que responde 404 (ou qualquer não-200) é listado emsitemaps/index.jsoncom seu status e emmeta.jsondiscoveryErrors. Um sitemap em outro host (robots.txt nomeando um de um site irmão, ou um índice listando um; www e apex contam como um host) é listado lá como{ url, host, skipped: "other host" }e nunca buscado, para que nenhuma de suas URLs entre no rastreamento. Duas URLs de sitemap com o mesmo nome de arquivo nunca se sobrescrevem: a segunda é salva com um sufixo do seu caminho de diretório (page-sitemap-es.xml).--exclude <prefix>[,<prefix>...]deixa partes do host de fora (sub-sites de um WordPress multisite como/president/, ou uma seção que o proprietário mantém): uma URL cujo caminho começa com um nunca é solicitada, seja um sitemap, as listas REST, um link ou um redirecionamento que leve até lá. Um sitemap sob um é listado emsitemaps/index.jsoncomo{ url, skipped: "excluded" }; um redirecionamento para um é registrado com esse destino, não solicitado; links para um permanecem no HTML salvo e são listados emlinks.jsonexcluded, nãointernal;meta.jsonexcludednomeia os prefixos e a linha de base os carrega. Prefixos e caminhos são comparados em uma forma, então/présidence/,/pr%c3%a9sidence/e/pr%C3%A9sidence/são o mesmo prefixo. Uma folha de estilo ou ícone raiz que redireciona para um não é seguido lá (a folha é listada com status"excluded").--resumeos mantém; um prefixo adicionado em--resumeremove o que já foi capturado sob ele (suas páginas com seus arquivospages/etext/, redirecionamentos dele, feeds e sitemaps sob ele, e folhas de estilo e scripts usados apenas por essas páginas) e imprime o que removeu.media.mjseassets.mjstambém pulam arquivos sob eles.node <skill-dir>/scripts/capture.mjs https://www.example.com --out captureEm seguida, a segunda passada do Wayback, quando
wayback-unverified.txtnão está vazio: ele solicita cada caminho arquivado uma vez, para que os que ainda redirecionam caiam emcapture/redirects.jsoncom origemseed(os redirecionamentos da linha de base os pegam) e o restante seja registrado com seu status eminventory.json.--seed,--seed-filee--include-querytodos se aplicam em--resume, e o Wayback Machine não é consultado novamente:node <skill-dir>/scripts/capture.mjs https://www.example.com --out capture --resume --seed-file capture/wayback-unverified.txt -
Media. Lista cada arquivo de mídia em
capture/media.jsone o salva em.conversion/media-cache/, o diretório de trabalho da conversão, que fica fora do git:node <skill-dir>/scripts/media.mjs --capture capture --download .conversion/media-cacheEle baixa seis arquivos por vez. Por padrão (
--sizes referenced) busca os originais e cada tamanho que o site usa: aquele para o qual uma página, folha de estilo, srcset, tag og ou sitemap aponta, ou cujo nome de arquivo aparece em qualquer lugar nas páginas, folhas de estilo ou scripts capturados (data-thumb, data-bg, configurações JSON, scripts de slider). Um tamanho do WordPress que apenas a lista de mídia REST nomeia é listado comdownloaded: false, reason: "unreferenced size"e não solicitado. Ele imprime a divisão, ex.920 originals + referenced sizes (downloaded), 4,520 unreferenced sizes (listed only): repita essa linha para a pessoa. Use--sizes allquando o proprietário disser que e-mails antigos ou outros sites podem linkar para esses tamanhos.Hosts que redimensionam por query string (WordPress VIP, Jetpack Photon:
photo.jpg?w=1024,?resize=300,200) servem cada tamanho no mesmo caminho. O original é o caminho simples, então é o que é solicitado e salvo; cada query string vista é listada sobvariants(não solicitada;--sizes allas salva como<path>%3F<query>sob uma pasta irmã,.conversion/media-cache-variants/, para que o cache de mídia que é enviado ou copiado para o repo contenha apenas caminhos simples). Quando o caminho simples responde um erro (4xx ou 5xx; um redirecionamento é registrado com sua localização, e um arquivo muito grande é solicitado novamente uma vez que o limite é aumentado), uma variante é salva em seu lugar e a entradadownloadedFromé a URL de onde veio. Uma query de cache-busting (sem parâmetrow,h,resize,crop,fit,quality,formatous, ex.?ver=3) é o mesmo arquivo, então é preferida e nada mais é marcado; caso contrário, a variante mais larga é salva e a entrada também dizresized: true. A execução imprime uma linha por arquivo e uma contagem (2 originals unavailable (resized: true) ...), baseline/media.json mantém ambos os campos, e a verificação de mídia repete a contagem comoN resized (original unavailable on live)sem falhar, já que compara com os bytes realmente salvos. Repita essa contagem para a pessoa e liste esses arquivos no plano e runbook como originais que o site ao vivo não serve mais. -
Templates. Agrupa as páginas que responderam 200 em
capture/templates.json. No WordPress, as páginas agrupam primeiro pela classe body do template (home,page,single-post,archive, classes de template) e uma página cuja marcação é claramente diferente (Jaccard abaixo de 0.5) se separa comopage-2; outras plataformas mesclam por marcação com Jaccard 0.6, comotemplate-<n>:node <skill-dir>/scripts/templates.mjs --capture capture -
Assets. Logotipo, favicon, apple-touch-icon, o manifesto web
<link rel=manifest>e cada fonte@font-faceemcapture/assets/, mais o/favicon.icoe/apple-touch-icon.pngraiz (root-favicon.*,root-apple-touch-icon.*) quandometa.jsoniconsos registrou com 200:node <skill-dir>/scripts/assets.mjs --capture captureO logotipo é procurado na página inicial dentro do
<header>primeiro, depois dentro de qualquer outro elemento cuja classe ou id nomeie um logotipo (.logo,.site-logo,#logo-wrap). Em cada um: um<img>cujo src, alt, class ou id tenha a palavra "logo" (não "logout"), depois um<svg>inline com "logo" em sua class, id, aria-label ou<title>(salvo comologo.svg,url: nullemassets/index.json; sua nota diz isso quando apenas<use>um símbolo definido em outro lugar na página, que renderiza vazio por conta própria), depois o primeiro<img>em um link para a página inicial, depois o primeiro<img>. Verifiqueassets/logo.*visualmente: um avatar de conta ou marca de patrocinador ainda pode vencer em um cabeçalho incomum. O favicon e apple-touch-icon são salvos como servidos a partir de seu href<link>, query string incluída, para que um que aponte para um redimensionamento (?w=32,?w=180) de um arquivo de uploads difira em bytes da entrada desse arquivo emmedia.json: mantenha o ícone salvo, não o original. -
Capturas de tela ao vivo, uma por template em 390, 768 e 1440, com o shooter de revisão 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). Apenas quando
npx --no-install lighthouse --versionresponder; nunca instale sem ser solicitado; se estiver faltando, diga isso nas notas (um salto, não uma aprovação). Executemkdir -p capture/lighthouse-live, depois uma execução porrepresentativeemtemplates.json, por vez: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 a captura em
capture/README.md; sua seção## Notesabre com linhas geradas, reescritas em cada execução (quantos caminhos do Wayback a segunda passada verificou e o que cada um respondeu: status, destino do redirecionamento; uma listagem do Wayback que falhou ou foi recusada por tamanho; cada URL ainda falhando após suas tentativas). Execute por último, e após qualquer reexecução:node <skill-dir>/scripts/readme.mjs --capture capture
| Script | Saída |
|---|---|
fingerprint | 0 concluído, 2 uso ou inalcançável, 3 bloqueio ou desafio de bot |
capture | 0 concluído, 2 uso, 3 parou em bloqueios, inalcançável, desafio de bot (tudo retomável), ou nenhuma página respondeu 200 |
media | 0 concluído (com arquivos ausentes incluídos), 2 uso, sem captura ou sem página que respondeu 200, 3 parou em bloqueios |
assets | 0 concluído (com arquivos ausentes incluídos), 2 uso ou sem captura, 3 parou em bloqueios |
templates | 0 concluído, 2 uso, sem inventory.json, ou "nenhuma página capturada" (nenhuma respondeu 200) |
readme | 0 concluído, 2 uso ou sem inventory.json |
shoot | 0 todas capturadas, 1 uma rota falhou, 2 uso, 3 parou em bloqueios |
Em saída 3
O site está bloqueando requisições ou não pode ser alcançado. Aguarde (minutos, não segundos), então:
fingerprint: execute novamente.capture: execute o mesmo comando com--resume. As URLs ainda na fila são repetidas
…
[truncado para tradução]