今年初,在拿到 Soomal.com 网站源码后,我将源码上传到自己 VPS 上。但由于原网站架构较为陈旧,不便于管理以及手机访问,近期我对网站进行重构,将其整体转换并迁移到 Hugo。
迁移方案设计
对于 Soomal.cc 的重构,我其实早有想法。此前也简单测试过,但发现存在不少问题,之前就放下此事了。
存在困难和挑战
-
原网站文章数量较大
Soomal 上共有 9630 篇文章,最早能追溯到 2003 年,总字数达到 1900 万。
Soomal 上共有 32.6 万张 JPG 图片,4700 多个图片文件夹,大多数图片都有 3 种尺寸,但也存在少量缺失的情况,整体容量接近 70 GB。
-
文章转换难度较大
由于 Soomal 网站源码中只有文章页面的 htm 文件,虽然这些文件可能都来自同一个程序制作。但我此前对这些 htm 文件进行简单测试时,发现页面内容架构也发生过多次变化,在不同阶段使用过不同的标签来命名,从 htm 中提取信息难度很大。
-
编码问题:Soomal 原来的 htm 都是使用 GB2312 编码,并且可能使用的是 Windows 服务器,在转换时需要处理特殊字符、转义字符问题。
-
图片问题:Soomal 网站中有大量图片内容,这些图片正是 Soomal 的精华所在,但图片使用了多种标签和样式,在提取图片链接和描述时,需要尽量避免缺漏。
-
标签和分类问题: Soomal 网站中标签数量庞大,有近 1.2 万个文章标签,另外有 20 多个文章分类。但在文章的 htm 文件中,缺少分类的内容,分类信息只能在 2000 多个分类切片 htm 中找到;而标签部分有些有空格,有些有特殊字符,还有一些同一篇文章重复标签的。
-
文章内容: Soomal 文章 htm 中包括正文、相关文章列表、标签等内容,都放在 DOC 标签下,我此前没留意到相关文章列表均使用的是小写的 doc 标签,造成测试时总是提取出错。这次主要是在打开网页时偶尔发现这个问题,才重新启动转换计划。
-
-
存储方案选择困难
我原本将 Soomal.cc 放在一台 VPS 上,几个月下来,发现虽然访问量不高,但流量掉的飞快,差不多用掉 1.5TB 流量。虽然是无限流量的 VPS,但看着也比较头疼。而在转换至 Hugo 后,主流的免费服务都很难使用,包括 Github 建议仓库小于 1GB,CloudFlare Pages 限制文件 2 万个, CloudFlare R2 存储限制文件 10GB,Vercel 和 Netlify 都限制流量 100GB 等等。
转换方法
考虑到 Soomal 转换为 Hugo 过程中可能存在的诸多问题,我设计了五步走的转换方案。
第一步:将 htm 文件转换为 markdown 文件
-
明确转换需求
- 提取标题:在
<head>
标签中提取出文章标题。例如,<title>刘延作品 - 谈谈手机产业链和手机厂商的相互影响 [Soomal]</title>
中提取谈谈手机产业链和手机厂商的相互影响
这个标题。 - 提取标签:使用关键词过滤方式,找到 Htm 中的标签位置,提取标签名称,并加上引号,解决标签命名中的空格问题。
- 提取正文:在
DOC
标签中提取出文章的正文信息,并截断doc
标签之后的内容。 - 提取日期、作者和页首图片信息:在 htm 中查找相应元素,并提取。
- 提取图片:在页面中通过查找图片元素标签,将
smallpic, bigpic, smallpic2, wrappic
等图片信息全部提取出来。 - 提取特殊信息:例如:二级标题、下载链接、表格等内容。
- 提取标题:在
-
转换文件 由于转换需求较为明确,这里我直接用 Python 脚本进行转换。
点击查看转换脚本示例
|
|
第二步:处理分类和摘要信息
受制于原来文章 htm 文件中没有包含分类信息影响,所以只能将文章分类目录单独进行处理,在处理分类时,可以顺便将文章摘要内容一并处理。
-
提取分类和摘要信息
主要是通过 Python 将 2000 多个分类页面中的分类和摘要信息提取出来,并处理成数据格式。
点击查看转换代码
|
|
-
将分类和摘要信息写入 markdown 文件
这一步比较简单,将上边提取出的分类和摘要数据逐个写入先前转换的 markdown 文件。
点击查看写入脚本
|
|
第三步:转换文章 frontmatter 信息
这一步主要是对输出的 markdown 文件中 frontmatter 部分进行修正,以适应 Hugo 主题需要。
- 将文章头部信息转按 frontmatter 规范进行修正 主要是处理包括特殊字符,日期格式,作者,文章首图、标签、分类等内容。
查看转换代码
|
|
- 精简标签和分类 Soomal.com 原本有 20 多个文章分类,但其中个别分类没有什么意义,比如“全部文章”分类,并且文章分类和文章标签有不少重复现象,为保证分类和标签的唯一性,对这部分进一步精简。另一个目的也是为了在最后生成网站文件时尽量减少文件数量。
查看精简标签和分类代码
|
|
第四步:精简图片数量
在 htm 转 md 文件的过程中,由于只提取文章内的信息,所以原网站中很多裁切图片已不再需要。为此,可以按照转换后的 md 文件内容,对应查找原网站图片,筛选出新网站所需的图片即可。
通过本步骤,网站所需图片数量从原来的 32.6 万下降到 11.8 万。
- 提取图片链接 从 md 文件中,提取出所有的图片链接。由于此前在转换图片连接时已经有统一的图片连接格式,所以操作起来比较容易。
查看提取代码
|
|
- 复制对应图片 使用上边提取出的图片链接数据,从原网站目录中查找对应文件并提取。过程中需要注意文件目录的准确性。
A.查看Windows中复制代码
|
|
B.查看Linux中复制代码
|
|
第五步:压缩图片体积
我此前已经对网站源图进行过一次压缩,但还不够,我期望是将图片容量压缩到 10 GB 以内,用以适应日后可能需要迁移到 CloudFlare R2 的限制要求。
- 将 JPG 转换为 Webp 我此前使用 webp 对图片压缩后,考虑到 htm 众多,为避免图片无法访问,仍以 JPG 格式将图片保存。由于这次需要搬迁到 Hugo,JPG 格式也就没必要继续保留,直接转换为 Webp 即可。另外,由于我网页已经设置 960px 宽度,考虑到网站体积,也没有引入 fancy 灯箱等插件,直接使用 960px 缩放图片可以进一步压缩体积。
实测经过这次压缩,图片体积下降到 7.7GB ,但是我发现图片处理逻辑还是有点小问题。主要是 Soomal 上不仅有很多竖版图片,也有不少横版图片,另外,960px 的宽度,在 4K 显示器下还是显得有点不够看。我最终按照图片中短边最大 1280px 质量 85% 的设定转换了图片,体积约 14GB,刚好可以放入我 20GB 硬盘的 VPS 中。另外我也按短边最大 1150px 质量 80% 测试了一下,刚好可以达到 10GB 体积要求。
查看图片转换代码
|
|
- 进一步压缩图片 本来我设计了这一步,即在前边转换+缩放后,假如图片未能压缩到10GB以下,就继续启用压缩,但没想到前一步就把图片问题解决,也就没必要继续压缩。但我还是测试了一下,按照短边最大 1280px 60% 质量压缩为 webp 后,总容量只有 9GB。
查看图片二次压缩代码
|
|
构建方案
选择合适 Hugo 模板
对于一个上万 md 文件的 Hugo 项目来说,选择模板真是很折磨人。
我试过用一款比较精美的模板测试,发现连续构建三个小时都没能生成结束;试过有的模板生成过程中不断的报错;试过有的模板生成文件数量超过 20 万个。
最后我选择了最稳妥的 PaperMod 模板,这个模板默认只有 100 多个文件,生成网站后文件总数不到 5 万,总体来说还算好。
虽然达不到 Cloudflare Page 2万个文件的限制标准,但也相当精简了,在 Github Pages 上构建花了 6 分半钟,在 Vercel 上构建花了 8 分钟。
不过,在构建过程中还是发生一些小问题,比如搜索功能,因为文章数据实在有点大,默认索引文件达到 80MB,几乎没有实用性,最后只能忍痛将索引限制在文章标题和摘要内容上。
还有站点地图生成问题,默认生成站点地图 4MB,在提交到 Google Console 后一直读取失败。Bing Webmaster 那边倒是没问题。
另外,分页问题也是个比较头疼的是。默认 12000 个标签,采用 20 篇文章一个页面,都能生成 6 万文件,在我将文章数提高到 200 一个页面后,仍然有 3.7 万个文件。与此同时,其他文件加起来也只有 1.2 万个。
不过,这个标签问题倒也也给了进一步改造的可能性,即只提取前使用数量在前 1000 位的标签,将其他标签作为标题的一部分。这样,应该可以将文件数控制在 2 万以内,满足 Cloudflare Pages 的限制需求。
选择合适的静态页面托管服务
由于 Hugo 项目本身只有 100MB 不到(其中文章 md 文件 80M),所以托管到 Github 没有任何问题。考虑到 Github Pages 访问速度较慢,我选择将网站部署到 Vercel,虽然 Vercel 只有 100GB 流量,但对于静态页面来说,应该是够用了。
选择合适的图片托管服务
目前仍在找。本想将图片托管到 Cloudflare R2,但看那个免费计划也有点不敢用,虽然有一定免费额度,但怕爆账单。先继续用我 7 美刀包年的假阿里云 VPS 吧。