简介:这是一款网站整站下载器,面向需要离线备份、整站镜像或批量抓取页面资源的网页开发与运维人员。其核心价值在于能递归抓取目标站点的页面结构、脚本及静态资源,并支持 ASP、JSP、PHP 等常见动态服务语言,帮助用户快速搭建本地副本或迁站素材。资源包采用 rar 压缩格式,整体大小约 540KB,由于源数据未提供具体文件总数与类型明细,因此不额外列举;工具本身属于轻量级便携方案,适合作为辅助脚本直接调用。目前已有 2183 人学习/下载,说明该工具在同类需求中有一定实用性。综合来看,用户可获得一个可执行的整站下载入口,节省逐页手工保存的时间,尤其适合批量镜像资讯类、文档类站点,配合排除规则即可灵活控制抓取范围。
1. 整站下载器到底能干什么:不是“另存为”,是把整个站搬回家
“网站整站下载器”这个词,搜索它的人通常带着一个很具体的需求:把一个网站完整拉到自己硬盘上,离线能看、能翻、能备份,最好连图片、CSS、JS 都不缺。这个标题翻译成实际操作,就是做一次站点镜像——用工具递归抓取页面里的所有链接,把 HTML、静态资源、甚至跨域引用的文件全部落盘,再改写链接路径让本地文件互相跳转正常。它解决的痛点是:在线查资料怕页面失效、做项目要留档、把别人的静态站结构拿来做参考,或者赶在网站改版前把内容整个备份下来。
这个方向适合谁?两类人。一类是刚接触命令行、想用 wget 一条命令搞定的小白;另一类是已经试过简单下载但发现图片裂了、翻页失效、动态内容抓不全的熟手。整站下载不是把网页“另存为”一次,而是一个递归遍历、资源提取、路径重写的完整流程。本文要讲的就是把这条路走通:从最小命令开始,逐步加参数,再处理动态站点的特殊方式,最后把常见的坑一条条排掉。先记住一件事:凡是靠“另存为”能解决的需求,都不需要整站下载器;需要它的场景,通常一条基础命令也搞不定。
2. 用 wget 做整站镜像:四条命令从入门到够用
wget 是 Linux/macOS 自带、Windows 也能用的下载工具,做整站镜像它是最轻的起点。核心思路就一句话:给 wget 一个起始 URL,让它递归地抓取页面里的链接,再把所有资源按目录结构存到本地。它像一个爬虫,但比写爬虫省掉了解析 HTML、去重、路径处理这些脏活。
2.1 最小的镜像命令:wget -r为什么不够,要加什么
很多人第一次尝试敲的是wget -r https://example.com,然后发现下载了一堆东西,但打开本地页面全是乱的。原因很简单:-r只负责递归,不负责“像个网站一样能离线用”。我一般会用一个最小可用的镜像命令:
wget -r -l 5 -p -k -E https://example.com/docs/参数拆开看:-r开启递归下载;-l 5限制递归深度为 5 层,防止爬到外链的无限跳转;-p下载页面显示所需的所有资源,包括图片、CSS、JS;-k把下载后的 HTML 里的链接改写成本地相对路径,这是离线能用的关键;-E给没有扩展名的文件补上.html,避免本地打开时被当成二进制文件。
这个命令适合中小型静态网站。注意-l 5不是随便填的:深度太小会漏掉深层页面,太大又容易把时间耗在无关链接上。对于文档站点,5 层通常足够;如果是论坛或博客,建议结合后面的-np参数限制范围。
2.2 限定域与限定目录:防止“下载整个互联网”
裸跑wget -r最翻车的场景是:网站首页有个友情链接,指向另一个站,wget 顺着爬过去了,然后那个站又链接了别的站……你本意是下载一个站,最后硬盘里塞了几万个无关文件。控制范围有两种写法:
wget -r -l 5 -p -k -E --domains example.com --no-parent https://example.com/docs/--domains example.com表示只接受来自该域名的链接,跨域链接忽略不计;--no-parent表示不访问起始目录的上级目录,配合https://example.com/docs/使用,就把抓取范围锁死在/docs/下。这两个参数是整站下载的“保险丝”,宁可先限制再放宽,不要一开始就全站裸跑。
还有一个容易被忽略的细节:--domains只影响链接的“跟随”,不影响-p对资源的下载。也就是说,如果页面引用了cdn.other-site.com上的图片,--domains拦不住它,需要加-D或-H来精确控制。实际使用中,我会先不加资源域名限制跑一遍,看日志里哪些域名出现频繁,再决定是否单独放行。
2.3 登录态与延时:镜像需要鉴权的内网文档站
很多需要整站下载的站点不是公开的,比如公司内部的 Confluence、某个需要登录才能看的教程站。wget 支持携带 Cookie 和请求头,常见的做法是:
wget -r -l 4 -p -k -E \ --header "Cookie: sessionid=abc123; user_token=xyz" \ --header "User-Agent: Mozilla/5.0" \ --wait=2 --random-wait \ https://internal.example.com/wiki/--header手写 Cookie 是最直接的方式,从浏览器开发者工具里复制即可,但注意有效期——很多站点会话一小时内就过期,如果站点大、下载时间长,建议把 Cookie 值换成长期有效的 token。--wait=2 --random-wait表示每次请求之间等待 2 秒并随机抖动,目的是降低对目标服务器的压力,也避免触发风控。
这里提一个经验点:大站镜像不要追求速度。并发拉满虽然快,但经常爬到一半 IP 被封,前功尽弃。wget 默认串行下载,也可以加-c断点续传,配合延时参数使用更稳。
3. 比 wget 更进一步的方案:HTTrack 与浏览器渲染级抓取
wget 对纯静态站点几乎无敌,但对现代网站——尤其是前端框架渲染的 SPA、需要滚动加载的页面、或者有复杂 JS 逻辑的站点——它就无能为力了。因为 wget 只解析 HTML 里已有的链接和资源,不会执行 JavaScript。这时需要切换到两类工具:专门做站点镜像的图形化工具,以及模拟真实浏览器的抓取方案。
3.1 HTTrack 的取舍:图形界面下的完整镜像
HTTrack 是与 wget 定位相似但更彻底的站点镜像工具,它最大的优点是自动处理目录结构、链接改写和资源提取,而且带图形界面,适合不熟悉命令行的读者。我在处理“需要完整保留站点结构”的镜像任务时,偶尔会用它的命令行模式跑批处理:
httrack https://example.com -O /data/mirror -v-O指定输出目录,-v显示详细日志。HTTrack 默认会尝试解析 JavaScript 里动态生成的链接(通过内置的爬虫规则),这比 wget 强一些,但也谈不上完整支持 SPA。它还会自动生成一个hts-cache目录存放索引信息,如果只想拿纯净的站点文件,记得镜像完成后手动清理。
HTTrack 的坑在于它对 HTTPS 证书较敏感,某些自签名证书站点会直接失败,需要加--disable-security-limit参数跳过验证。不过这个参数会降低安全性,只建议在内网环境使用。
3.2 动态站点用 Playwright 抓:模拟浏览器,存 DOM 快照
遇到 Vue/React 渲染的站点,wget 和 HTTrack 都不好使。这类站点的 HTML 里往往只有一个空的根节点,真正的页面内容由 JS 在浏览器里“画”出来。最可靠的方案是模拟浏览器访问,等页面渲染完成后,把渲染结果保存下来。我常用的做法是用 Playwright 写一个轻量脚本:
import asyncio from playwright.async_api import async_playwright async def snapshot(url: str, output: str): async with async_playwright() as p: browser = await p.chromium.launch() page = await browser.new_page() # 等待网络空闲,确保大部分资源加载完成 await page.goto(url, wait_until="networkidle", timeout=30000) # 保存完整页面(单文件,内含 CSS 和图片) await page.screenshot(path=output, full_page=True) # 保存渲染后的 HTML html = await page.content() with open(f"{output}.html", "w", encoding="utf-8") as f: f.write(html) await browser.close() asyncio.run(snapshot("https://example.com", "./snapshot"))wait_until="networkidle"是关键参数,表示等待网络空闲后才算加载完成,这能覆盖大部分懒加载场景;page.content()拿到的是 JS 执行完之后的完整 DOM,而非初始 HTML。这套方案的局限也很明确:它只能保存“一个页面”的快照,不能自动递归整站。想做成整站下载器,需要自己维护一个待抓 URL 队列,循环调用snapshot(),同时把前端路由解析出来。
3.3 方案选型表:什么场景用哪个工具
| 站点类型 | 推荐工具 | 关键参数/动作 | 主要风险 |
|---|---|---|---|
| 纯静态 HTML 站 | wget | -r -l 5 -p -k -E | 链接范围控制不当,爬出站 |
| 带相对路径的文档站 | wget +--no-parent | 限制在目标目录内 | 深度不够漏页面 |
| 需要登录的站点 | wget +--header Cookie | 复制浏览器 Cookie | 会话过期导致大量 403 |
| 静态但结构复杂的站 | HTTrack | 图形界面或-O指定输出 | 证书问题导致失败 |
| SPA/JS 渲染站 | Playwright 自写脚本 | wait_until="networkidle" | 需要自建 URL 队列,工程量大 |
选型逻辑不复杂:先判断目标站点的 HTML 里有没有完整内容——浏览器里右键“查看源代码”,如果内容都在,用 wget 就够;如果源码里只有空壳,再考虑 Playwright。HTTrack 是中间选项,适合静态但页面数量大、且需要自动处理链接改写的场景。
4. 下载之后的事:文件校验、资源补齐与离线浏览
下载完成不等于整站下载结束。真正衡量一次镜像是否成功的标准是:把本地目录当服务器跑起来,网站的所有内页图片、样式、跳转都正常。这一步经常暴露问题——wget 下载时静默跳过的某些资源,会让离线浏览的页面“缺胳膊少腿”。
4.1 用本地 HTTP 服务验证镜像完整性
用python3 -m http.server起一个本地服务,是验证镜像最直观的方式。我把下载目录起服务后,会重点看三处:首页样式是否加载、文章页图片是否显示、内页跳转是否回得到首页。
cd /data/mirror/example.com python3 -m http.server 8080 # 浏览器访问 http://localhost:8080如果样式丢了,多半是-k失败或 CSS 被跨域规则拦截;如果图片裂了,看是不是懒加载页面没触发 wget 的资源提取;如果跳转回不到首页,通常是--domains把站内其他子域的链接跳过了。遇到问题,返回去检查 wget 的日志文件,找到robots或ERROR开头的行,定位是哪个规则误杀。
4.2 检查文件级的完整性:数量、大小与空文件
镜像完成后我会跑一个简单的统计命令,看这站到底拉下来多少东西:
find /data/mirror -type f | wc -l find /data/mirror -type f -size 0 -ls du -sh /data/mirror三个命令分别看:文件总数、空文件列表、总大小。空文件是整站下载最常见的“假成功”——服务器返回 200 但内容为空,wget 也会创建文件,页面因此残废。如果空文件集中在某个目录,大概率是该目录需要特定请求头(如 Referer),可以用 wget 的--referer参数补上;如果空文件散落各处,考虑是不是目标站有反爬策略,随机返回空响应。
4.3 资源文件的跨域域名处理:把 CDN 资源也拉下来
这是最容易让人骂“玄学”的地方。站点使用了 CDN,图片存储在cdn.example.com,但页面 HTML 在www.example.com。wget 的--domains默认只跟随一个域,CDN 资源被忽略。解决方法有两个:
# 方法一:把 CDN 域加入允许列表 wget -r -p -k -E --domains example.com,cdn.example.com https://example.com/ # 方法二:用 -H 允许跨域宿主 wget -r -p -k -E -H --span-hosts https://example.com/--span-hosts会把所有引用了资源的跨域域名都视为可下载对象,但危险之处在于它不区分“资源”和“页面”——如果页面上有个外链文字链,它也会尝试去下载整个外链站。稳妥的做法是用方法一,先确认 CDN 域名再手写列表。我处理这类问题时,会先用浏览器抓一次请求日志,把所有资源域名列出来,再决定哪些放行。
5. 整站下载避坑指南:四个高频翻车现场与排查手段
整站下载这个事,十个里有八个会翻车。不是工具不行,是站点远比想象中复杂。下面四条是高频踩坑记录,每条都是我的真实经历,按“现象→原因→解决”写给你。
5.1 下了三个小时,本地打开首页全是乱码
现象:页面 HTML 文件能打开,但文字全是乱码,CSS 也没生效。原因:目标站点是 UTF-8 编码,但 wget 下载时没有正确识别,或 HTML 里没声明字符集,本地浏览器默认用了非 UTF-8 解码。解决:镜像前先确认响应头里的Content-Type有没有charset=utf-8,如果缺失,用 wget 的--header强制加上自己想要的字符集,或者下载后用iconv批量转码。其实常见的更直接原因是 HTML 里有lang="zh-CN"但没写<meta charset>,这时只能事后补转码。
5.2 页面能打开但图片全部裂开
现象:浏览器控制台显示一张图片都没有,检查本地目录发现图片文件名都在,但大小为 0。原因:目标站图片服务器做了防盗链,要求请求必须带Referer头,wget 默认裸请求被拒绝。解决:给 wget 加上 Referer 和相关域名参数:
wget -r -l 5 -p -k -E \ --referer=https://example.com/ \ --domains example.com,img.example.com \ https://example.com/--referer统一用首页地址做来源,大多数防盗链就能过。如果还不行,看响应状态码——401/403 说明服务端校验了更复杂的头,需要把浏览器的完整请求头逐一搬过来。
5.3 爬到一半 IP 被封
现象:wget 日志里连续出现 403,再往后直接是连接超时。原因:速度太快,或者--wait启动后有个等待值过短,目标服务器做了访问频率限制。解决:一是放慢速度,--wait=5 --random-wait把间隔拉到 5 秒以上;二是加--limit-rate=500k限制带宽,双管齐下基本能避免触发封禁。注意--limit-rate对单连接有效,如果开了并发,总速率会翻倍,要按并发数调低单值。
5.4 动态页面用 wget 抓下来只有空壳
现象:HTML 文件下载下来了,打开一看<body>里什么都没有,或者只有一个小标记。原因:站点使用 JS 渲染,wget 不执行 JavaScript,拿到的只是初始模板。解决:按本文 3.2 节的 Playwright 方案处理,或者在命令行下用 wkhtmltopdf 之类能执行 JS 的工具把页面“渲染后”的完整 DOM 拿下来。这一步没有通用命令,必须写脚本。我见过有人在 wget 后面加--execute robots=off试图解决,那只会加快爬取速度,对 JS 渲染毫无帮助。
6. 增量更新与深度定制:让整站下载成为可持续用的技能
整站下载不是一次性任务——网站会更新,镜像也需要跟着更新。如果每次更新都从头重新下载,时间和带宽成本太高。这里分享两个我常用的进阶技巧,一个是增量更新策略,一个是针对“压缩包型站点”的快速镜像。
6.1 增量更新:用.wget-hsts和条件请求避开重复下载
wget 支持有条件请求,只下载服务器上“改过”的文件。核心参数是-N(时间戳检测)和-nc(不重新下载已存在的文件):
wget -r -l 5 -p -k -E -N -nc https://example.com/docs/-N会对比本地文件和远程文件的修改时间,如果远程文件没变就跳过;-nc避免重复下载已存在的资源。这比重新整站拉一遍靠谱得多。但注意:-nc在部分场景下会导致文件不更新,因为它的逻辑是“已存在就跳过”,所以它适合“新增和修改都不多”的场景,频繁更新的站建议只用-N。
增量更新还有个更细的做法:配合-X /path排除某些目录,或者用--reject排除指定文件类型。比如文档站的 PDF 更新不频繁,增量时直接排掉,节省流量。
6.2 结构分析:镜像前先摸清站点的目录树
在敲任何下载命令前,我习惯先用一条命令看清站点结构:
curl -s https://example.com/ | grep -oE 'href="[^"]+"' | head -50这个命令把首页上所有链接地址列出来,能快速判断站点的内容组织方式——是目录式(/docs/xxx/)还是标签式(/tag/xxx/),是分页(?page=2)还是无限滚动。链接规律直接决定-l深度和--no-parent的配置方向。比如看到链接是/blog/2024/03/12/post-name,就能确认这是个博客,深度设 3 层足够,且要确保--no-parent不会把/blog/下面各月份目录拦掉。
另外看一个站能不能“整站下载”,我的标准是看它的页面数。百万级页面的站点,不要试图一次性全下——先把最重要的栏目下下来,再谈全站。这是做整站下载的底线认知:工具能解决技术问题,但解决不了规模问题。诊断清楚规模后,再选工具、设参数,才能把“下载整个网站的所有资源”从口号变成可交付的结果。
以上是我从无数个镜像任务里沉淀下来的完整路径:先辨站点类型,再选工具链,然后调参数、验结果,最后用增量更新维持镜像的新鲜度。每次遇到新站,我仍然会先跑一遍最小命令,看输出日志确认行为符合预期,才敢放开全量下载——这个习惯救过我很多次。希望帮到你。
本文还有配套的精品资源,点击获取