Files
go-site-clone/HTML_PATH_REPLACE.md
2025-11-24 18:59:19 +08:00

8.6 KiB
Raw Blame History

HTML 资源路径替换功能说明

📋 功能概述

在下载网站时,自动将 HTML 文件中的所有资源绝对路径转换为相对路径,使得离线浏览时资源能够正确加载。


支持的资源类型

1. CSS 样式表

<!-- 替换前 -->
<link href="https://example.com/css/style.css" rel="stylesheet">

<!-- 替换后 -->
<link href="./css/style.css" rel="stylesheet">

2. JavaScript 脚本

<!-- 替换前 -->
<script src="https://example.com/js/app.js"></script>

<!-- 替换后 -->
<script src="./js/app.js"></script>

3. 图片资源

<!-- 替换前 -->
<img src="https://example.com/images/logo.png" alt="Logo">

<!-- 替换后 -->
<img src="./images/logo.png" alt="Logo">

4. 视频资源

<!-- 替换前 -->
<video src="https://example.com/videos/demo.mp4"></video>
<source src="https://example.com/videos/demo.webm">

<!-- 替换后 -->
<video src="./videos/demo.mp4"></video>
<source src="./videos/demo.webm">

5. 音频资源

<!-- 替换前 -->
<audio src="https://example.com/audio/music.mp3"></audio>

<!-- 替换后 -->
<audio src="./audio/music.mp3"></audio>

6. CSS 中的 URL

/* 替换前 */
background-image: url('https://example.com/images/bg.jpg');
background: url("https://example.com/images/pattern.png");
background: url(https://example.com/images/texture.jpg);

/* 替换后 */
background-image: url('./images/bg.jpg');
background: url("./images/pattern.png");
background: url(./images/texture.jpg);

🔧 技术实现

核心函数

1. replaceHTMLResourcePaths()

主函数,负责替换 HTML 中的所有资源路径。

func replaceHTMLResourcePaths(htmlContent string, baseURL string) string {
    // 解析基础 URL
    // 使用正则表达式匹配各种资源标签
    // 调用 convertToRelativePath 转换每个 URL
    // 返回修改后的 HTML
}

2. convertToRelativePath()

将绝对 URL 转换为相对路径。

判断逻辑

  • 只替换同域名的资源
  • 跳过外部域名资源
  • 跳过 data:、javascript:、mailto: 等协议
  • 跳过已经是相对路径的资源
func convertToRelativePath(resourceURL, baseURL, baseHost, baseScheme, basePath string) string {
    // 1. 验证 URL 类型
    // 2. 检查是否同域名
    // 3. 计算相对路径
    // 4. 返回转换结果
}

3. calculateRelativePath()

计算两个路径之间的相对路径。

示例

basePath := "/pages/about/"
targetPath := "/css/style.css"

// 结果:../../css/style.css

📊 路径转换示例

示例 1同级目录

当前页面https://example.com/index.html
资源路径https://example.com/style.css

转换结果:./style.css

示例 2子目录

当前页面https://example.com/index.html
资源路径https://example.com/css/main.css

转换结果:./css/main.css

示例 3上级目录

当前页面https://example.com/pages/about.html
资源路径https://example.com/css/style.css

转换结果:../css/style.css

示例 4深层嵌套

当前页面https://example.com/blog/2024/11/post.html
资源路径https://example.com/images/logo.png

转换结果:../../../images/logo.png

示例 5外部资源不替换

当前页面https://example.com/index.html
资源路径https://cdn.example.com/jquery.js

转换结果https://cdn.example.com/jquery.js保持不变

🚫 不会被替换的资源

1. Data URL

<img src="data:image/png;base64,iVBORw0KG...">
<!-- 保持不变 -->

2. JavaScript 伪协议

<a href="javascript:void(0)">Click</a>
<!-- 保持不变 -->

3. 锚点链接

<a href="#section1">Go to Section 1</a>
<!-- 保持不变 -->

4. 外部域名资源

<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
<!-- 保持不变(不同域名)-->

5. 已经是相对路径

<img src="./images/photo.jpg">
<link href="../css/style.css">
<!-- 保持不变 -->

🎯 使用场景

1. 离线浏览

下载整站后,可以在没有网络的情况下正常浏览,所有资源都能正确加载。

2. 网站备份

保存网站的完整副本,包括所有页面和资源,路径关系正确。

3. 网站迁移

将网站从一个域名迁移到另一个域名,资源路径自动适配。

4. 本地开发

在本地环境测试网站,无需配置虚拟主机。


🔍 处理流程

1. 下载 HTML 文件
   ↓
2. 读取 HTML 内容
   ↓
3. 解析基础 URL当前页面地址
   ↓
4. 使用正则表达式匹配资源标签
   ├─ <link href="...">
   ├─ <script src="...">
   ├─ <img src="...">
   ├─ <video src="...">
   ├─ <audio src="...">
   └─ url(...)
   ↓
5. 对每个匹配项:
   ├─ 提取 URL
   ├─ 判断是否需要替换
   ├─ 计算相对路径
   └─ 替换原 URL
   ↓
6. 保存修改后的 HTML 文件

📝 正则表达式说明

CSS 链接

regexp: `(<link[^>]*?href=[\"'])([^\"']+)([\"'][^>]*?>)`
匹配: <link ... href="URL" ...>

JavaScript 脚本

regexp: `(<script[^>]*?src=[\"'])([^\"']+)([\"'][^>]*?>)`
匹配: <script ... src="URL" ...>

图片

regexp: `(<img[^>]*?src=[\"'])([^\"']+)([\"'][^>]*?>)`
匹配: <img ... src="URL" ...>

视频和 Source

regexp: `(<(?:video|source)[^>]*?src=[\"'])([^\"']+)([\"'][^>]*?>)`
匹配: <video src="URL">  <source src="URL">

CSS URL

regexp: `(url\\([\"']?)([^\"')]+)([\"']?\\))`
匹配: url("URL")  url('URL')  url(URL)

⚠️ 注意事项

1. 同域名限制

只替换与当前页面同域名的资源,确保不破坏 CDN 等外部资源。

2. 编码问题

假设 HTML 文件使用 UTF-8 编码,其他编码可能需要额外处理。

3. 动态加载

通过 JavaScript 动态加载的资源可能无法自动替换,需要手动处理。

4. 绝对路径限制

页面内如果使用了 <base> 标签,可能影响相对路径的解析。

5. 特殊字符

URL 中包含特殊字符(如空格、中文)可能需要 URL 编码。


🔄 完整示例

原始 HTML

<!DOCTYPE html>
<html>
<head>
    <link href="https://example.com/css/style.css" rel="stylesheet">
    <script src="https://example.com/js/app.js"></script>
    <style>
        body { background: url('https://example.com/images/bg.jpg'); }
    </style>
</head>
<body>
    <img src="https://example.com/images/logo.png" alt="Logo">
    <video src="https://example.com/videos/intro.mp4"></video>
    <script src="https://cdn.example.com/library.js"></script>
</body>
</html>

转换后 HTML

<!DOCTYPE html>
<html>
<head>
    <link href="./css/style.css" rel="stylesheet">
    <script src="./js/app.js"></script>
    <style>
        body { background: url('./images/bg.jpg'); }
    </style>
</head>
<body>
    <img src="./images/logo.png" alt="Logo">
    <video src="./videos/intro.mp4"></video>
    <script src="https://cdn.example.com/library.js"></script>
    <!-- 注意:外部 CDN 资源保持不变 -->
</body>
</html>

🚀 性能优化

1. 正则表达式预编译

可以将正则表达式编译为全局变量,避免重复编译:

var (
    cssRegex    = regexp.MustCompile(`(<link[^>]*?href=[\"'])([^\"']+)([\"'][^>]*?>)`)
    scriptRegex = regexp.MustCompile(`(<script[^>]*?src=[\"'])([^\"']+)([\"'][^>]*?>)`)
    // ... 其他正则
)

2. 批量替换

使用 strings.Replacer 进行批量替换可能更高效(但需要先收集所有需要替换的 URL

3. HTML 解析器

对于复杂的 HTML可以考虑使用 golang.org/x/net/html 进行 DOM 解析,更准确但性能稍低。


🐛 调试日志

函数会输出详细的转换日志:

路径替换: https://example.com/css/style.css -> ./css/style.css
路径替换: https://example.com/images/logo.png -> ./images/logo.png
路径替换: https://example.com/js/app.js -> ./js/app.js

可以通过日志查看哪些资源被替换,哪些被跳过。


📌 总结

HTML 资源路径替换功能使得下载的网站能够:

离线完整浏览 - 所有资源路径正确
保持原有结构 - 目录关系不变
智能判断 - 只替换需要替换的资源
保护外部资源 - CDN 等外部资源保持不变
性能优化 - 使用正则批量处理

这使得整站下载功能更加完善和实用!