Vitepress+EdgeOne Pages快速迁移旧网站内容

去年在阿里云码上公益平台报名了一个公益项目,这周收到了公益组织负责人的邮件,请求帮助开发一个用于查询志愿者服务时长的网页,另外该组织官网的服务器即将到期,需要尽快迁移服务器上的网站数据。

第一个需求比较简单,使用飞书多维表格的查询视图很快就完成了;第二个就相对复杂了,各种debuff因素加满:

  1. 官网是基于老旧的CMS系统做的,没有导出文章、图片的功能
  2. 密码丢了,无法远程登录服务器
  3. 服务器几天后就到期,时间紧

通过对比AI工具给出的几种建议方案,最终决定使用Vitepress+腾讯云EdgeOne Pages快速搭建网站,迁移旧网站的文章。

本文详细记录使用Vitepress+腾讯云EdgeOne Pages迁移旧网站内容的过程。

下载旧网站文章、图片

  1. 登录网站CMS后台,打开浏览器开发者工具,通过DOM获取网站文章列表
  2. 通过fetch方法发送网络请求,提取响应网页中的文章内容(富文本,HTML),保存文章内容到本地
const items = [];
const rows = document.querySelectorAll('tr[height="35"]');
for (const row of rows) {
const cells = row.querySelectorAll('td');
const id = cells.item(1).textContent.trim();
const links = cells.item(2).querySelectorAll('a');
const category = links.item(0).textContent.slice(1, -1);
const title = links.item(1).textContent.trim();
const updatedAt = cells.item(3).textContent.trim();
items.push({
id,
category,
title,
updatedAt,
});
} function stringToDOM(htmlString) {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, "text/html");
return doc;
} function downloadAsFile(filename, content) {
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
a.style.display = "none";
document.body.appendChild(a); // 触发点击事件,模拟用户点击下载
a.click(); // 释放URL对象,避免内存泄漏
URL.revokeObjectURL(url);
document.body.removeChild(a);
} function sleep(delayTime = 1000) {
return new Promise(resolve => setTimeout(resolve, delayTime));
} const recordIds = ["580", "579", ...];
for (const id of recordIds) {
fetch(`${baseUrl}/article_edit.php?aid=${id}`)
.then(response => response.text())
.then(html => {
const element = stringToDOM(html);
const content = element.querySelector('textarea#body');
if (content) {
downloadAsFile(`${id}.txt`, content.value);
}
});
await sleep(1500);
}
  1. 通过Python lxml解析HTML,抽取其中的图片标签,获取图片链接
  2. 根据图片链接,下载图片到本地
from lxml import etree

parser = etree.HTMLParser()

def find_images(html: str) -> list[str]:
"""解析HTML,抽取img标签中图片的路径"""
tree = etree.fromstring(html, parser)
images = []
for image in tree.xpath('//img'):
image_url = image.get('src')
if image_url.startswith('/uploads'):
images.append(image_url)
return images images = []
for file in (data_dir / 'articles').rglob('*.txt'):
with open(file, mode='r', encoding='utf8') as fp:
html = fp.read()
images.extend(find_images(html)) print('Found {} images'.format(len(images)))

网站文章转Markdown

Vitepress推荐把图片放到public目录下,在Markdown中通过以/为前缀的路径进行引用,为了保证网站文章在转Markdown后图片路径是正确的,需要在转换之前更新HTML中图片标签的src属性。

  1. 更新图片标签的src属性
  2. 使用Python markdownify把网站文章转换为Markdown
from lxml import etree
from markdownify import markdownify as md parser = etree.HTMLParser() def handle_image_tags(title, html: str) -> str:
"""解析HTML,过滤图片标签,更新图片标签的src属性"""
tree = etree.fromstring(html, parser)
for index, image in enumerate(tree.xpath('//img')):
image_url = image.get('src')
image_name = Path(image_url).name
if not image_url.startswith('/uploads') or image_name not in valid_images:
image.getparent().remove(image)
continue
image.set('src', '/{}'.format(image_name))
image.set('alt', '{}-{}'.format(title, index + 1))
return etree.tostring(tree, encoding='utf8', method='html').decode('utf8') def convert_article_to_markdown(title: str, created_at: str, content: str) -> str:
"""HTML文章转Markdown"""
metadata = """---
outline: deep
title: {}
author: 江津阳光社工
date: {}
version: 1.0
--- # {}""".format(title, created_at, title)
converted = md(content, heading_style='ATX').strip()
return metadata + '\n' + converted table = str.maketrans(r'\/:*?"<>|', '_' * 9)
filename = title.translate(table) + '.md'

Vitepress项目快速开始

  1. 参考Vitepress快速开始初始化项目,启动起来
  2. 把转换后的网站文章移动docs目录下
  3. 安装插件VitePress Sidebar,自动生成侧边栏
  4. 安装插件vitepress-plugin-image-viewer,点击预览文章中的图片
  5. 编辑Vitepress配置文件docs/.vitepress/config.mjs,最后上传代码到Github:
import { defineConfig } from 'vitepress'
import { withSidebar } from 'vitepress-sidebar'; function nav() {
return [
{
text: '关于我们',
items: [
{
text: '荣誉资质',
link: '/about-us/awards-and-certifications/中心资质.md',
},
{
text: '组织架构',
link: '/about-us/organizational-structure/江津阳光社工中心组织架构.md',
},
]
},
// ...
]
} // https://vitepress.dev/reference/site-config
const vitePressOptions = {
title: "江津阳光社会工作服务中心",
description: "让儿童都能健康快乐成长,让社区更加和谐幸福。",
lang: "zh-CN",
locales: {
"/": {
label: "简体中文",
lang: "zh-CN",
},
},
lastUpdated: true,
themeConfig: {
nav: nav(), search: {
provider: "local",
options: {
placeholder: "搜索文章",
translations: {
button: { buttonText: "搜索文章" },
modal: {
searchBox: {
resetButtonTitle: "清除查询条件",
resetButtonAriaLabel: "清除查询条件",
cancelButtonText: "取消",
cancelButtonAriaLabel: "取消",
},
startScreen: {
recentSearchesTitle: "搜索历史",
noRecentSearchesText: "没有搜索历史",
saveRecentSearchButtonTitle: "保存至搜索历史",
removeRecentSearchButtonTitle: "从搜索历史中移除",
favoriteSearchesTitle: "收藏",
removeFavoriteSearchButtonTitle: "从收藏中移除",
},
errorScreen: {
titleText: "无法获取结果",
helpText: "你可能需要检查你的网络连接",
},
footer: {
selectText: "选择",
navigateText: "切换",
closeText: "关闭",
searchByText: "搜索提供者",
},
noResultsScreen: {
noResultsText: "无法找到相关结果",
suggestedQueryText: "你可以尝试查询",
reportMissingResultsText: "你认为该查询应该有结果?",
reportMissingResultsLinkText: "点击反馈",
},
},
},
},
}, footer: {
copyright: `版权所有 2019-${new Date().getFullYear()} 重庆市江津阳光社会工作服务中心`
}, docFooter: {
prev: '上一页',
next: '下一页'
}, outline: {
label: '页面导航'
}, lastUpdated: {
text: '最后更新于',
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium'
}
}, langMenuLabel: '多语言',
returnToTopLabel: '回到顶部',
sidebarMenuLabel: '菜单',
darkModeSwitchLabel: '主题',
lightModeSwitchTitle: '切换到浅色模式',
darkModeSwitchTitle: '切换到深色模式',
skipToContentLabel: '跳转到内容',
}
}; const vitePressSidebarOptions = [
{
documentRootPath: 'docs',
scanStartPath: 'about-us',
basePath: '/about-us/',
resolvePath: '/about-us/',
collapsed: true,
capitalizeFirst: true,
useTitleFromFrontmatter: true,
useFolderTitleFromIndexFile: true,
},
// ...
]; export default defineConfig(withSidebar(vitePressOptions, vitePressSidebarOptions));

注意:由于VitePress Sidebar插件默认按目录名生成侧边栏,需要在目录下添加index.md文件,指定名称才能让侧边栏显示为中文。

---
title: 荣誉资质
---

EdgeOne Pages零帧起手

EdgeOne Pages是基于Tencent EdgeOne基础设施打造的前端开发和部署平台,专为现代Web开发设计,帮助开发者快速构建、部署静态站点和无服务器应用。通过集成边缘函数能力,实现高效的内容交付和动态功能扩展,支持全球用户的快速访问。

  1. 连接Github仓库
  2. 填写构建参数:
    • 输出目录:docs/.vitepress/dist
    • 编译命令:pnpm run docs:build
    • 安装命令:pnpm install
  3. 点击开始部署,部署完成后就可以通过临时(3小时)的域名访问网页了,添加自定义域名后,即可通过自己的域名访问网站。

参考材料

Vitepress+EdgeOne Pages快速迁移旧网站内容的更多相关文章

  1. WordPress快速增加百度收录,加快网站内容抓取

    本文已同步到专业技术网站 www.sufaith.com, 该网站专注于前后端开发技术与经验分享, 包含Web开发.Nodejs.Python.Linux.IT资讯等板块. 利用百度站长平台提供的链接 ...

  2. 基于django快速开发一个网站(一)

    基于django快速开发一个网站(一) *  创建虚拟环境.基于虚拟环境创建django==2.0.0和图片加载库和mysql数据库驱动 1. 创建目录并创建虚拟环境 ╰$ mkdir Cornuco ...

  3. ECS服务器快速迁移

    ECS服务器快速迁移 前提 一.停机 二.创建镜像 三.复制镜像 前提 服务器都在同一个区域,举例:华南1(深圳) 同一个账号 具体迁移步骤如下: 一.停机 先从阿里云ECS控制台,将要迁移的两台EC ...

  4. 利用github pages创建简单的网站

    github.com 作为最流行的源代码管理工具已经风靡全球,同时在依托于github也衍生出了各种各样的应用,比如可以利用github搭建博客系统等等. 先换个话题,我们每人手头都或多或少有些&qu ...

  5. 10个开源的PHP网站内容管理系统

    1. DEDE -这是一款国内开源的cms,作者是一个个人,能做出如此功能的cms,是相当不错的.2007版功能十分强大,希望能改善之前数据量一大,更新静态页就很慢的缺点.因为开源,有较多的玩家和拥护 ...

  6. 使用CDN对动态网站内容加速有效果吗

      个资源文件,有利于减少原始服务器的压力.        缓存网页内容        对于动态网站而言,部分访问量大的网页内容可能改观不大,好比论坛的首页,置顶的帖子很少泛起大转变,因此这样的网页可 ...

  7. Docker: 快速搭建LNMP网站平台

    快速搭建LNMP网站平台 步骤: 1.自定义网络(这里建立一个自定义网络,名字叫 lnmp, 让LNMP网站的服务,都加入这个自定义网络)docker network create lnmp2.创建M ...

  8. •搭建LAMP环境及快速部署双网站并实现基于域名的虚拟主机

    本节所讲内容: 实战:搭建LAMP环境及快速部署双网站并实现基于域名的虚拟主机 LAMP架构:??? Linux+Apache+Mysql+PHP Linux+Apache+Mysql/MariaDB ...

  9. 用 Serverless 快速搭建个人相册网站

    日常生活中我们经常会拍摄一些视频.照片等,这些文件会占用比较多的存储空间.本文将介绍一种方法:利用 ThumbsUp 工具,结合 Serverless Framework 的 component 快速 ...

  10. PHP学习笔记:通过curl实现采集网站内容

    关于curl,请各位同学自行百度,我直接上案例. 首先开启你的curl拓展,在php.ini文件把curl拓展开启,即取消extension=php_curl.dll的分号. eg:利用curl采集网 ...

随机推荐

  1. 天地图接口Python代码详解

    天地图是中国国家测绘地理信息局推出的一款权威.全面的在线地理信息系统,提供了丰富的卫星影像.地形.矢量图等地图资源.开发者可以通过天地图提供的API接口,实现地图的展示.搜索.定位等功能.本文将详细介 ...

  2. 【Python】【爬虫】【爬狼】001_urllib_get_获取响应结果页面代码

    情况说明 本节课我们要处理的网站是 www.yhdmp.cc 注意:腾讯报毒该网址.问题不大,基本这种盗版动漫的网站都会报毒吧.如果不放心可以自己找个其他的网站爬,我这个也是随便找的. 该网站搜索提交 ...

  3. Springboot上传文件大小限制处理

    今天在开发过程中遇到一个文件上传的问题 io.undertow.server.RequestTooBigException: UT000020: Connection terminated as re ...

  4. Qt编写地图综合应用14-离线地图下载

    一.前言 网上其实有很多各种各样的离线地图下载器,大部分都是要收费的,免费的要么是限制了下载的瓦片数量或者级别,要么是下载的瓦片图打上了水印,看起来很难看,由于经常需要用到离线地图,摆脱这个限制,特意 ...

  5. Qt开源作品8-通用控件移动

    一.前言 在做一些项目的过程中,有一种应用场景是需要拖动设备在一个容器中,自由拖动摆放到合适的位置,然后保存对应设备的坐标位置信息,在软件启动好以后自动加载配置好的坐标位置信息,将每个设备移动到对应的 ...

  6. findHomography()函数详解

    indHomography: 计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列) ,使用最小均方误差或者RANSAC方法 函数功能:找到两个平面之间的转换矩阵. Mat cv::findHom ...

  7. DVWA靶场Brute Force (暴力破解) 漏洞low(低),medium(中等),high(高),impossible(不可能的)所有级别通关教程及代码审计

    暴力破解 暴力破解是一种尝试通过穷尽所有可能的选项来获取密码.密钥或其他安全凭证的攻击方法.它是一种简单但通常无效率的破解技术,适用于密码强度较弱的环境或当攻击者没有其他信息可供利用时.暴力破解的基本 ...

  8. 零基础Windows Server搭建部署Word Press 博客系列教程(2):从菜鸡到高手之Windows Server 环境配置

    上一篇:零基础Windows Server搭建部署Word Press 博客系列教程(1):从萌新到菜鸡之云主机配置与备案 本篇教程主要介绍在云主机上安装好相关组件并配置好环境,直至网站上线. 1.之 ...

  9. w3cschool-MyBatis 教程

    参考 https://www.w3cschool.cn/mybatis/mybatis-dyr53b5w.html MyBatis 入门 SqlSessionFactoryBuilder用 SqlSe ...

  10. nginx中的正则表达式,location路径匹配规则和优先级

    前言,我这里验证的nginx-v1.23.2单机环境下的nginx中的正则表达式.location路径匹配规则和优先级. 先准备好环境,基础配置是这样 nginx/conf/conf.d/host.c ...