Communitygithub.com

ethanplusai/astro-conversion-kit

抓取并保存现网网站的所有内容(HTML、文本、元数据、资源等),用于后续重建或转换。支持断点续传。

astro-conversion-kit 是什么?

该技能(`capture-site`)旨在完整克隆一个现网网站,以便后续的转换或重建工作完全基于本地捕获的数据进行。其核心原则是:只读、有节地抓取网页,绝不提交表单或登录。技能包含一整套 Node.js 脚本,按序执行:指纹识别、HTML 及资源抓取、媒体文件缓存、模板聚类、Logo/字体等关键资产提取、多宽度截图,以及可选的 Lighthouse 性能评估。它具备智能的速率限制自适应机制,可应对 429/503 等反爬策略,并在连续失败后自动暂停。支持 `--resume` 断点续传,并生成详细的 `README.md` 报告。适用于 Astro 等静态站点生成器的迁移或重建场景。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ethanplusai/astro-conversion-kit/tree/HEAD/skills/capture-site

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

capture-site

一次性地将现网站点所提供的一切内容保存下来,这样后续的所有步骤都可以基于这个本地副本进行。

黄金法则

现网站点只读,并且抓取副本在创建后也只读。 这些脚本仅发出有节律的 GET 和 HEAD 请求;绝不提交表单、登录或手动获取以填补遗漏。一旦生成了笔记,capture/ 目录下的任何内容都不会被编辑:它是所有关卡读取的证据。

何时使用

转换流程的第二步(convert-site 会运行它),或者任何时候需要对现网站点进行盘点(预发布或新站点是 launch-audit 的任务)。如果抓取过程因阻塞而退出(退出码 3),可以按下面的方法进行恢复。

节流策略

每个脚本都发送桌面版 Chrome 的 User-Agent 头。抓取脚本(capture、media、assets、fingerprint)共享一个按域名限制的限流器:默认情况下,请求开始之间间隔 400 毫秒,最多并发 4 个(media 为 6 个),因此一个响应迅速的域名可以在几分钟内完成读取。Chromium 步骤(shoot、css-coverage、styles)一次只加载一个页面,间隔 500 毫秒,launch-audit 和 pre-launch 则使用自己的节流策略。限流器会自动适应:

  • 收到 429 或 503 响应时,该域名的延迟将加倍(最多 32 倍),并且并发数降为 一次一个请求;在连续收到 30 秒正常响应后,限制会逐步恢复(延迟减半,并发数加一),直至回到默认值。
  • 如果某个响应的耗时超过 5 秒,该域名的并发请求数将减半(在减半期间不会再触发此操作),恢复方式相同:每连续 30 秒正常响应,并发数增加一个。
  • 403 或网络错误的处理方式与之前的连续三次停止逻辑相同。

--polite 模式是旧有的节流方式:一次一个请求,间隔 2500 毫秒(适用于 capture、media、assets)。如果目标站点位于带有机器人验证墙的共享主机上(例如 SiteGround 的 /.well-known/sgcaptcha/,或者对少量快速请求就返回 429 或 503 的主机),或者当之前的运行因阻塞而停止时,请从一开始就使用该模式:使用 --polite 恢复。--delay <ms> 和 --concurrency <n> 可以覆盖默认值或 --polite 模式。对现网站点请保持默认值或使用 --polite 模式(--delay 0 仅用于本地测试数据),并且绝不要更改 --ua 来绕过封锁。

  • capture 会预先获取最多 --concurrency 个队列中的 URL,并按队列顺序记录它们,因此抓取结果与逐一爬取相同。每个 URL 会重试 3 次。如果一个 URL 在被重试 3 次后仍然被阻塞(403、429、503 或网络错误),其状态和 attempts 会被记录在 inventory.json 中(如果是 sitemap 或 REST 列表中的 URL,则记录在 meta.json 的 discoveryErrors 中),然后爬取继续。只有在 连续 3 个不同的 URL 都耗尽重试次数且之间没有任何成功请求 时,抓取才会停止,此时状态被保存,这三个 URL 会被重新加入队列并赋予新的重试机会。它从不请求 wp-admin、wp-login、xmlrpc.php 或 ?s= 搜索页面。
  • media 每个文件尝试 3 次:如果持续收到 429 或 503,则立即停止;403 或网络错误会被记录为该文件的状态,当连续出现 3 个这样的文件(按响应到达顺序)时停止。已经在下载的文件会允许完成。每处理 100 个文件保存一次 media.json,因此被中断的运行可以从接近断点处恢复。
  • fingerprint 不重试:如果首页被封锁,或返回的是机器人验证页面,则退出码为 3。assets 和 shoot 会在遇到连续 3 个被封锁的响应后停止。

命令序列

在将包含 capture/ 目录的文件夹(即站点仓库的根目录)下运行。<skill-dir> 是本技能文件夹的绝对路径,存放于已执行 npm install 的工具包副本中(脚本会导入其包)。每个脚本都能打印 --help;请运行它以获取帮助,而不是阅读源代码。按以下顺序,将每个步骤作为单独的命令运行:

  1. 指纹识别,然后读取它所命名的平台参考(如下表所示):

    node <skill-dir>/scripts/fingerprint.mjs https://www.example.com
    
  2. 抓取。 发现方式包括:站点地图(robots.txt 中的每行 Sitemap:,加上平台的默认索引)、REST 列表(WordPress,当指纹识别发现 REST 时;--no-rest 可以跳过)、链接爬取,以及 --seed <path> 或 --seed-file <file>(每行一个路径或 URL,# 开头的行为注释)用于爬虫无法到达的路径(旧 URL、旧的 .htaccess)。爬取完成后,爬虫未找到的 Wayback 路径会写入 wayback-unverified.txt(--no-wayback 可跳过;如果列出失败,会在 10 秒后重试一次,然后 meta.json 中的 wayback 会记录 failed)。?p= 短链接会被记录但不会验证,除非你传递了 --verify-shortlinks 参数。爬取完成后,它会请求一个不可能存在的路径(/<32 hex>/)一次,这样站点的 404 页面会被保存为 pages/404.html(记录在 meta.json 的 notFound 中;如果站点对那个路径返回 200 或重定向,则不会保存任何页面),并且会分别请求 /favicon.ico 和 /apple-touch-icon.png 各一次,跟随重定向(meta.json 中的 icons:包含 { status, file, contentType, bytes } 的路径);如果返回 200,则逐字节保存为 assets/root-favicon.ico 或 assets/root-apple-touch-icon.png(如果返回的是 HTML 内容,则不保存并添加备注;如果文件超过 5 MB,状态为 "too-large"),并且 assets.mjs 会将其作为 kind: "root-icon" 列出在 assets/index.json 中,附带其 path,以便构建过程将其放置到位。URL 使用大写百分比转义符作为键(%c3%a9 和 %C3%A9 视为同一个 URL),因此如果一个页面被两种拼写方式链接,只会被抓取一次。robots.txt 中引用的站点地图如果返回 404(或任何非 200 状态码),会在 sitemaps/index.json 中列出其状态,并在 meta.json 的 discoveryErrors 中记录。位于其他主机上的站点地图(robots.txt 引用姊妹站点的,或索引列出了其他主机的;www 和 apex 视为同一个主机)会被列为 { url, host, skipped: "other host" } 且永不获取,因此它的 URL 不会进入爬取队列。两个具有相同文件名的站点地图 URL 不会互相覆盖:第二个站点地图会使用其目录路径的后缀保存(例如 page-sitemap-es.xml)。--exclude <prefix>[,<prefix>...] 可以排除主机上的部分路径(例如 WordPress 多站点中的子站点如 /president/,或站点所有者保留的部分):路径以此前缀开头的 URL 永远不会被请求,无论站点地图、REST 列表、链接还是重定向指向它。前缀下的站点地图会在 sitemaps/index.json 中列为 { url, skipped: "excluded" };重定向到排除路径的请求会被记录,但目标不会被请求;指向排除路径的链接会保留在已保存的 HTML 中,并在 links.json 中列为 excluded,而不是 internal;meta.json 的 excluded 字段会记录这些前缀,并且基线也会包含它们。前缀和路径的比较使用规范化形式,因此 /présidence/、/pr%c3%a9sidence/ 和 /pr%C3%A9sidence/ 被视为同一个前缀。如果样式表或根图标重定向到一个排除前缀下的路径,则不会跟随(该样式表会以状态 "excluded" 列出)。--resume 会保留已有的排除前缀;在 --resume 时添加新的前缀会移除该前缀下已捕获的内容(包括其 pages/ 和 text/ 文件、来自该前缀的重定向、该前缀下的 feeds 和站点地图,以及仅这些页面使用的样式表和脚本),并打印已移除的内容。media.mjs 和 assets.mjs 也会跳过它们前缀下的文件。

    node <skill-dir>/scripts/capture.mjs https://www.example.com --out capture
    

    然后,当 wayback-unverified.txt 不为空时,执行 Wayback 第二轮抓取:它会对每个归档路径请求一次,因此那些仍然返回重定向的路径会落入 capture/redirects.json,其来源为 seed(基线的重定向处理程序会拾取它们),其余路径则以其状态记录在 inventory.json 中。--seed、--seed-file 和 --include-query 在 --resume 时均适用,并且不会再查询 Wayback Machine:

    node <skill-dir>/scripts/capture.mjs https://www.example.com --out capture --resume --seed-file capture/wayback-unverified.txt
    
  3. 媒体文件。 列出 capture/media.json 中的每个媒体文件,并将其保存到 .conversion/media-cache/,即转换的工作目录,该目录不会被纳入 git 版本控制:

    node <skill-dir>/scripts/media.mjs --capture capture --download .conversion/media-cache
    

    它会一次下载六个文件。默认情况下(--sizes referenced),它获取原始文件以及站点使用的每种尺寸:即页面、样式表、srcset、og 标签或站点地图指向的尺寸,或者其文件名出现在任何已捕获页面、样式表或脚本中的尺寸(data-thumb、data-bg、JSON 设置、滑块脚本)。仅由 REST 媒体列表命名的 WordPress 尺寸会被列为 downloaded: false, reason: "unreferenced size" 且不会请求。它会打印拆分情况,例如 920 originals + referenced sizes (downloaded), 4,520 unreferenced sizes (listed only):将该行信息告诉用户。当站点所有者表示旧邮件或其他站点可能链接到这些尺寸时,请使用 --sizes all。

    通过查询字符串调整大小的主机(WordPress VIP、Jetpack Photon:photo.jpg?w=1024、?resize=300,200)在相同的路径上提供每种尺寸。原始文件是裸路径,因此这就是被请求和保存的内容;每个看到的查询字符串都会在 variants 下列出(不请求;--sizes all 会将其保存为 <path>%3F<query> 到一个同级文件夹 .conversion/media-cache-variants/ 中,因此上传或复制到仓库中的媒体缓存只包含裸路径)。当裸路径返回错误时(4xx 或 5xx;重定向会在 downloadFrom 及其 location 中记录,并且过大的文件会在容量限制提高后再次请求),一个变体将被保存到其位置,并且条目的 downloadedFrom 将是提供它的 URL。缓存清理型查询字符串(不含 w、h、resize、crop、fit、quality、format 或 s 参数,例如 ?ver=3)是同一文件,因此会优先选择它,并且不会标记其他内容;否则,最宽的变体将被保存,并且条目还会包含 resized: true。运行会为每个文件打印一行,并显示计数(2 originals unavailable (resized: true) ...),baseline/media.json 会同时保留这两个字段,并且媒体关卡会在不失败的前提下重复计数 N resized (original unavailable on live),因为它与实际保存的字节数进行比较。将该计数告诉用户,并在计划和操作手册中列出这些文件,作为现网站点不再提供的原始文件。

  4. 模板。 将返回 200 的页面聚类到 capture/templates.json。在 WordPress 上,页面首先按模板 body class 分组(home、page、single-post、archive、模板类),并且一个标记明显不同的页面(Jaccard 相似度低于 0.5)会作为 page-2 拆分出来;其他平台按 Jaccard 相似度 0.6 合并标记,作为 template-<n>:

    node <skill-dir>/scripts/templates.mjs --capture capture
    
  5. 资产。 将 Logo、favicon、apple-touch-icon、<link rel=manifest> 的 Web 清单以及所有 @font-face 字体提取到 capture/assets/ 中,此外还包括根目录的 /favicon.ico 和 /apple-touch-icon.png(root-favicon.*、root-apple-touch-icon.*),前提是 meta.json 的 icons 记录它们返回了 200:

    node <skill-dir>/scripts/assets.mjs --capture capture
    

    Logo 首先在首页的 <header> 内部查找,然后在其 class 或 id 包含“logo”的其他元素(如 .logo、.site-logo、#logo-wrap)中查找。在每个元素中:首先查找其 src、alt、class 或 id 包含单词“logo”(但不包含“logout”)的 <img>,然后查找包含“logo”在其 class、id、aria-label 或 <title> 中的内联 <svg>(保存为 logo.svg,在 assets/index.json 中 url: null;其备注会说明它是否只 <use> 了页面中其他地方定义的符号,这会导致独立渲染时为空),然后查找链接到首页的链接中的第一个 <img>,然后查找第一个 <img>。请用肉眼检查 assets/logo.*:在某些不寻常的 header 中,一个账户头像或赞助商标记仍然可能胜出。Favicon 和 apple-touch-icon 按其 <link> href 提供的样式保存,包括查询字符串,因此如果它们指向上传文件的调整大小版本(?w=32、?w=180),则其字节会与 media.json 中该文件的条目不同:保留保存的图标,而不是原始文件。

  6. 现网截图,每种模板在 390、768 和 1440 三种宽度下拍摄,使用视觉审查截图工具:

    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
    
  7. Lighthouse(可选)。 仅当 npx --no-install lighthouse --version 有响应时才执行;绝不未经请求安装它;如果缺少 Lighthouse,请在笔记中说明(作为跳过的步骤,而非失败的步骤)。运行 mkdir -p capture/lighthouse-live,然后按顺序为 templates.json 中的每个 representative 运行一次:

    npx --no-install lighthouse https://www.example.com/ --quiet --chrome-flags="--headless=new" --output json --output html --output-path capture/lighthouse-live/home
    
  8. README。 将抓取摘要汇总到 capture/README.md 中;其 ## Notes 部分以生成的描述行开头,每次运行时都会重写(包括第二轮 Wayback 验证的路径数量以及各自的响应状态或重定向目标;Wayback 列表失败或由于大小被拒绝;以及所有在重试后仍然失败的 URL)。最后运行该步骤,以及在任何重新运行之后:

    node <skill-dir>/scripts/readme.mjs --capture capture
    
脚本退出码
fingerprint0 完成,2 用法错误或不可达,3 被封锁或遇到机器人验证
capture0 完成,2 用法错误,3 因阻塞、不可达、机器人验证而停止(均可恢复),或没有页面返回 200
media0 完成(包含缺失文件),2 用法错误,没有抓取内容或没有返回 200 的页面,3 因阻塞停止
assets0 完成(包含缺失文件),2 用法错误或没有抓取内容,3 因阻塞停止
templates0 完成,2 用法错误,没有 inventory.json,或“没有已捕获的页面”(均未返回 200)
readme0 完成,2 用法错误或没有 inventory.json
shoot0 全部拍摄,1 某个路由失败,2 用法错误,3 因阻塞停止

关于退出码 3

站点正在阻止请求或无法到达。等待片刻(数分钟,而非秒),然后:

  • fingerprint:重新运行。
  • capture:使用 --resume 运行相同的命令。仍然在队列中的 URL 将被重试。

…

[因翻译而截断]

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

ethanplusai/astro-conversion-kit

Convert a live website (WordPress first; Drupal, Webflow, Squarespace, Wix and static sites too) into a static Astro site with the same URLs, content, head tags, media, redirects and look, proven by parity gates and a pixel-level visual review, ending in one pull request, a noindexed staging deploy and a launch runbook. Use when asked to convert, rebuild, migrate or clone a site to Astro, when handed a site URL with this kit's link, to resume a conversion from .conversion/state.json, or with --apply <id> to apply one suggestion as a proposal.

ethanplusai/astro-conversion-kit

Audit a live or staging website and report what would go wrong at launch — crawl and inventory, indexability, redirects for a domain cutover, links, images, forms, accessibility, performance, analytics, content sanity, and full-page screenshots for a visual pass. Use before or right after a site launch, when asked to QA, audit, or review a website, when a site is moving to a new domain, or when somebody asks whether a site is ready to go live. Read-only: it never submits a form, clicks a control, or edits anything.

ethanplusai/astro-conversion-kit

Freeze a site capture into baseline/ and prove an Astro build matches it — every route, redirect (one hop, through a simulation of the host), SEO head field, visible text, internal link, media file, sitemap entry, feed, form, third-party script and security header — with approved differences in exceptions.json and improvements in proposals.json. Use after a capture to build the baseline, when compiling redirects.csv for Vercel or Cloudflare, before calling any conversion page done, when a gate fails and needs reading, or to check a staging deploy against the baseline.

ethanplusai/astro-conversion-kit

The moment DNS moves and for the thirty days after — verifies the cutover (DNS propagation, certificate, http and www redirects, the noindex, robots and sitemap on the live host, every redirect the audit mapped, forms, analytics, the staging copy, the old host, security headers), diffs production against the pre-launch baseline, and schedules the watch. Use when asked did the launch work, is the site live, what should I check after launch, the domain just switched, or when a site went live in the last month and something looks wrong. It is read-only and exits 0 whatever it finds.

相关技能