找回密码
 立即注册
首页 业界区 业界 Vitepress+EdgeOne Pages快速迁移旧网站内容

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

迫蔺 2025-6-4 22:27:34
Vitepress+EdgeOne Pages快速迁移旧网站内容


目录

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

    • 下载旧网站文章、图片
    • 网站文章转Markdown
    • Vitepress项目快速开始
    • EdgeOne Pages零帧起手
    • 参考材料


去年在阿里云码上公益平台报名了一个公益项目,这周收到了公益组织负责人的邮件,请求帮助开发一个用于查询志愿者服务时长的网页,另外该组织官网的服务器即将到期,需要尽快迁移服务器上的网站数据。
第一个需求比较简单,使用飞书多维表格的查询视图很快就完成了;第二个就相对复杂了,各种debuff因素加满:

  • 官网是基于老旧的CMS系统做的,没有导出文章、图片的功能
  • 密码丢了,无法远程登录服务器
  • 服务器几天后就到期,时间紧
通过对比AI工具给出的几种建议方案,最终决定使用Vitepress+腾讯云EdgeOne Pages快速搭建网站,迁移旧网站的文章。
本文详细记录使用Vitepress+腾讯云EdgeOne Pages迁移旧网站内容的过程。
下载旧网站文章、图片


  • 登录网站CMS后台,打开浏览器开发者工具,通过DOM获取网站文章列表
  • 通过fetch方法发送网络请求,提取响应网页中的文章内容(富文本,HTML),保存文章内容到本地
  1. const items = [];
  2. const rows = document.querySelectorAll('tr[height="35"]');
  3. for (const row of rows) {
  4.     const cells = row.querySelectorAll('td');
  5.     const id = cells.item(1).textContent.trim();
  6.     const links = cells.item(2).querySelectorAll('a');
  7.     const category = links.item(0).textContent.slice(1, -1);
  8.     const title = links.item(1).textContent.trim();
  9.     const updatedAt = cells.item(3).textContent.trim();
  10.     items.push({
  11.         id,
  12.         category,
  13.         title,
  14.         updatedAt,
  15.     });
  16. }
  17. function stringToDOM(htmlString) {
  18.     const parser = new DOMParser();
  19.     const doc = parser.parseFromString(htmlString, "text/html");
  20.     return doc;
  21. }
  22. function downloadAsFile(filename, content) {
  23.     const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
  24.     const url = URL.createObjectURL(blob);
  25.     const a = document.createElement("a");
  26.     a.href = url;
  27.     a.download = filename;
  28.     a.style.display = "none";
  29.     document.body.appendChild(a);
  30.     // 触发点击事件,模拟用户点击下载
  31.     a.click();
  32.     // 释放URL对象,避免内存泄漏
  33.     URL.revokeObjectURL(url);
  34.     document.body.removeChild(a);
  35. }
  36. function sleep(delayTime = 1000) {
  37.         return new Promise(resolve => setTimeout(resolve, delayTime));
  38. }
  39. const recordIds = ["580", "579", ...];
  40. for (const id of recordIds) {
  41.     fetch(`${baseUrl}/article_edit.php?aid=${id}`)
  42.     .then(response => response.text())
  43.     .then(html => {
  44.         const element = stringToDOM(html);
  45.         const content = element.querySelector('textarea#body');
  46.         if (content) {
  47.             downloadAsFile(`${id}.txt`, content.value);
  48.         }
  49.     });
  50.     await sleep(1500);
  51. }
复制代码

  • 通过Python lxml解析HTML,抽取其中的图片标签,获取图片链接
  • 根据图片链接,下载图片到本地
  1. from lxml import etree
  2. parser = etree.HTMLParser()
  3. def find_images(html: str) -> list[str]:
  4.     """解析HTML,抽取img标签中图片的路径"""
  5.     tree = etree.fromstring(html, parser)
  6.     images = []
  7.     for image in tree.xpath('//img'):
  8.         image_url = image.get('src')
  9.         if image_url.startswith('/uploads'):
  10.             images.append(image_url)
  11.     return images
  12. images = []
  13. for file in (data_dir / 'articles').rglob('*.txt'):
  14.     with open(file, mode='r', encoding='utf8') as fp:
  15.         html = fp.read()
  16.     images.extend(find_images(html))
  17. print('Found {} images'.format(len(images)))
复制代码
网站文章转Markdown

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

  • 更新图片标签的src属性
  • 使用Python markdownify把网站文章转换为Markdown
  1. from lxml import etree
  2. from markdownify import markdownify as md
  3. parser = etree.HTMLParser()
  4. def handle_image_tags(title, html: str) -> str:
  5.     """解析HTML,过滤图片标签,更新图片标签的src属性"""
  6.     tree = etree.fromstring(html, parser)
  7.     for index, image in enumerate(tree.xpath('//img')):
  8.         image_url = image.get('src')
  9.         image_name = Path(image_url).name
  10.         if not image_url.startswith('/uploads') or image_name not in valid_images:
  11.             image.getparent().remove(image)
  12.             continue
  13.         image.set('src', '/{}'.format(image_name))
  14.         image.set('alt', '{}-{}'.format(title, index + 1))
  15.     return etree.tostring(tree, encoding='utf8', method='html').decode('utf8')
  16. def convert_article_to_markdown(title: str, created_at: str, content: str) -> str:
  17.     """HTML文章转Markdown"""
  18.     metadata = """---
  19. outline: deep
  20. title: {}
  21. author: 江津阳光社工
  22. date: {}
  23. version: 1.0
  24. ---
  25. # {}""".format(title, created_at, title)
  26.     converted = md(content, heading_style='ATX').strip()
  27.     return metadata + '\n' + converted
  28. table = str.maketrans(r'\/:*?"<>|', '_' * 9)
  29. filename = title.translate(table) + '.md'
复制代码
Vitepress项目快速开始


  • 参考Vitepress快速开始初始化项目,启动起来
  • 把转换后的网站文章移动docs目录下
  • 安装插件VitePress Sidebar,自动生成侧边栏
  • 安装插件vitepress-plugin-image-viewer,点击预览文章中的图片
  • 编辑Vitepress配置文件docs/.vitepress/config.mjs,最后上传代码到Github:
  1. import { defineConfig } from 'vitepress'
  2. import { withSidebar } from 'vitepress-sidebar';
  3. function nav() {
  4.   return [
  5.     {
  6.       text: '关于我们',
  7.       items: [
  8.         {
  9.             text: '荣誉资质',
  10.             link: '/about-us/awards-and-certifications/中心资质.md',
  11.         },
  12.         {
  13.             text: '组织架构',
  14.             link: '/about-us/organizational-structure/江津阳光社工中心组织架构.md',
  15.         },
  16.       ]
  17.     },
  18.     // ...
  19.   ]
  20. }
  21. // https://vitepress.dev/reference/site-config
  22. const vitePressOptions = {
  23.   title: "江津阳光社会工作服务中心",
  24.   description: "让儿童都能健康快乐成长,让社区更加和谐幸福。",
  25.   lang: "zh-CN",
  26.   locales: {
  27.     "/": {
  28.       label: "简体中文",
  29.       lang: "zh-CN",
  30.     },
  31.   },
  32.   lastUpdated: true,
  33.   themeConfig: {
  34.     nav: nav(),
  35.     search: {
  36.       provider: "local",
  37.       options: {
  38.         placeholder: "搜索文章",
  39.         translations: {
  40.           button: { buttonText: "搜索文章" },
  41.           modal: {
  42.             searchBox: {
  43.               resetButtonTitle: "清除查询条件",
  44.               resetButtonAriaLabel: "清除查询条件",
  45.               cancelButtonText: "取消",
  46.               cancelButtonAriaLabel: "取消",
  47.             },
  48.             startScreen: {
  49.               recentSearchesTitle: "搜索历史",
  50.               noRecentSearchesText: "没有搜索历史",
  51.               saveRecentSearchButtonTitle: "保存至搜索历史",
  52.               removeRecentSearchButtonTitle: "从搜索历史中移除",
  53.               favoriteSearchesTitle: "收藏",
  54.               removeFavoriteSearchButtonTitle: "从收藏中移除",
  55.             },
  56.             errorScreen: {
  57.               titleText: "无法获取结果",
  58.               helpText: "你可能需要检查你的网络连接",
  59.             },
  60.             footer: {
  61.               selectText: "选择",
  62.               navigateText: "切换",
  63.               closeText: "关闭",
  64.               searchByText: "搜索提供者",
  65.             },
  66.             noResultsScreen: {
  67.               noResultsText: "无法找到相关结果",
  68.               suggestedQueryText: "你可以尝试查询",
  69.               reportMissingResultsText: "你认为该查询应该有结果?",
  70.               reportMissingResultsLinkText: "点击反馈",
  71.             },
  72.           },
  73.         },
  74.       },
  75.     },
  76.     footer: {
  77.       copyright: `版权所有 © 2019-${new Date().getFullYear()} 重庆市江津阳光社会工作服务中心`
  78.     },
  79.     docFooter: {
  80.       prev: '上一页',
  81.       next: '下一页'
  82.     },
  83.     outline: {
  84.       label: '页面导航'
  85.     },
  86.     lastUpdated: {
  87.       text: '最后更新于',
  88.       formatOptions: {
  89.         dateStyle: 'short',
  90.         timeStyle: 'medium'
  91.       }
  92.     },
  93.     langMenuLabel: '多语言',
  94.     returnToTopLabel: '回到顶部',
  95.     sidebarMenuLabel: '菜单',
  96.     darkModeSwitchLabel: '主题',
  97.     lightModeSwitchTitle: '切换到浅色模式',
  98.     darkModeSwitchTitle: '切换到深色模式',
  99.     skipToContentLabel: '跳转到内容',
  100.   }
  101. };
  102. const vitePressSidebarOptions = [
  103.     {
  104.         documentRootPath: 'docs',
  105.         scanStartPath: 'about-us',
  106.         basePath: '/about-us/',
  107.         resolvePath: '/about-us/',
  108.         collapsed: true,
  109.         capitalizeFirst: true,
  110.         useTitleFromFrontmatter: true,
  111.         useFolderTitleFromIndexFile: true,
  112.     },
  113.     // ...
  114. ];
  115. export default defineConfig(withSidebar(vitePressOptions, vitePressSidebarOptions));
复制代码
注意:由于VitePress Sidebar插件默认按目录名生成侧边栏,需要在目录下添加index.md文件,指定名称才能让侧边栏显示为中文。
  1. ---
  2. title: 荣誉资质
  3. ---
复制代码
EdgeOne Pages零帧起手

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

  • 连接Github仓库
  • 填写构建参数:

    • 输出目录:docs/.vitepress/dist
    • 编译命令:pnpm run docs:build
    • 安装命令:pnpm install

  • 点击开始部署,部署完成后就可以通过临时(3小时)的域名访问网页了,添加自定义域名后,即可通过自己的域名访问网站。
1.png

参考材料


  • 飞书多维表格的查询视图
  • VitePress由Vite和Vue驱动的静态站点生成器
  • EdgeOne Pages文档

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册