2024年,如何打造惊艳的个人博客/出版系统并且赚点小钱?

几年前,我就推荐过用Markdown写作静态博客。静态博客几乎是零托管成本,比较适合个人博客起步。Markdown便于本地搜索,也可当作是个人知识库方案。

现在有了新的进展。我不仅构建了一个视觉上相当不错的个人网站,还美化了github、构建了个人出版系统 – 将文章导出为排版精美的图片和pdf的能力。


这一方案的核心是Mkdocs和Mkdocs-material。前者是Python技术文档构建系统,后者是与之适配的主题。我在《Python能做大项目》这本书中,深入介绍过这两种技术。

现在,基于这两种技术,我们可以走得更远:不仅可以撰写技术文档,更可以打造博客和门户网站。

下图就是截取的大富翁量化的网站界面:

在这里插入图片描述


你可以在大富翁量化网站上看到它最新的样式。更有创意的是,虽然它只是一个静态网站,但你每次刷新它,都能看到一些新的内容 – 至少配图会变!

这是首页。菜单栏、搜索这些是常规配置。标签云、首页的卡片式布局,是提升站点气质的地方。

所有的文档都有版本管理,我使用了github来托管文档和图片,所以,也顺便把github的个人主页美化了一下:

75%

实在说,之前我没有想过,github主页也可以做得像个人网站。不得不说一张好图,能大大提升颜值。


此外,作为创作者,我还希望自己的文章能在多个渠道上发布,包括公众号、知乎、CSDN和小红书,有时候还需要把文章导出为PDF。这些渠道采用的技术大不相同,它们的排版要求也不一样,所以,要想不把时间无谓地浪费在枯燥、重复的排版上,我们就得用好各种工具。

1. Mkdocs + Mkdocs - Material

基础搭建我都写在《Python能做大项目》这本书的第10章中了,这里我们只介绍如何开通博客功能,以及定制首页。

Material自带了博客插件,我们只需要在配置中启用它(以及其它相关插件):

plugins:- awesome-pages:collapse_single_pages: true- blog:post_excerpt_separator: <!--more-->- tags:tags_file: tags.md- rss:match_path: "(blog|articles)/.*"categories:- categories- tagsdate_from_meta:as_creation: "date"as_update: truedatetime_format: "%Y-%m-%d %H:%M"default_timezone: Asia/Shanghaiuse_git: false

其中rss插件需要安装mkdocs-rss-plugin插件。关于如何定制标签云,请参考Code Inside Out上的这篇文章。

该文也提到了如何实现最新博文的功能。不过,博主最后决定自己用Python撸一个方案,以实现本文开头提到的效果 – 动态和卡片式,并且能自动更新github的profile。

2. 自定义脚本生成卡片式首页和github profile

这个方案主要使用了python-frontmatter库。通过一个脚本,搜索articles和blog目录下所有的md文件,读取它们的front matter,再按日期排序,将最新发表的文章和博文的摘要、日期、title和首图抽取出来,通过模板生成一个新的README.md文件,放到项目根目录下。

github会读取这个文件作为我们的profile,mkdocs-material也会根据这个文件,生成网站首页。

这个readme.md实际上是一个带部分html标签的md片段。我先用脚本生成了供mkdocs使用的README.md,待网站发布后,再生成供github的profile使用的readme.md。区别主要在于,github的profile中不能使用’<style>'标签来定义样式,它只允许在README.md中html标签中,使用少量的样式语法。

!!! tip
如果对这个方案的细节感兴趣,可以直接访问zillionare这个项目。mkdocs-material的定制在docs/overrides目录下。构建Readme.md的脚本在根目录下,名字为publish.py。

为了生成响应式的卡片布局,我使用了bootstrap中card样式。它简单到只要把父容器声明为card-columns类,card元素的样式声明为card就可以了。此外,为了根据不同的屏幕大小,显示不同的card列数,可以使用媒体查询和column-count属性,在docs/assets/templates/homepage.tpl文件中有示例。

在publish.py脚本中,我使用了frontmatter来提取文章中的meta,但它的速度有点慢。不过这是一个使用多进程加速的好场景:

metas = []
articles = glob.glob("./docs/articles/**/*.md", recursive=True)
with ProcessPoolExecutor() as executor:results = executor.map(extract_article_meta, articles)metas.extend([meta for meta in results if meta is not None])

这样就可以多进程处理文件了。最终结果会汇总到metas这个数组中。

!!! tip “图片自动换新技巧”
图片自动换新,可以给静态网站增加动态内容。让读者每次访问,都有不一样的感觉。这是通过unsplash网站的gallery功能来实现的。unsplash是一个免费图片资源共享网站,提供了大量高清、很高质量的免费图片。如果我们将img元素的url指向’https://source.unsplash.com/random/360x200?{word}'这样的地址,unsplash就会返回一个360x200,并且其类别为word的图片。

3. 发布到小红书

小红书发文不能超过1000字,并且很难格式化。如果要分享文字、代码并且做到混排,惟一的方法就是将其转换成为图片。这个步骤有点繁琐,不过,这也成为一种壁垒,导致深度内容在小红书上比较稀缺。因此,如果能搞定格式排版,这样就可以有效地利用小红书的分发。

我的方案是使用slidev。它是一个基于markdown语法来创作在线演示的方案,提供了转换为图片的功能。因此,我们基于mkdocs+material创作的文档,只要加上少量的标记和定制,就可以很容易地转换成为图片。



要实现这个功能,在安装slidev之后,先进行主题定制。最重要的是cover layout的定制。左图就是我之前为小红书日更设计的一个首页样式。

我们可以设计多个样式,在导出时,使用下面的命令:

npx slidev export --format png -t /path/to/slidev_themes/special_theme_dir --output /tmp/xhs /path/to/src.md

我们需要在markdown内容中的合适位置,增加"—"作为分页符,这样就能导出一页页适合在小红书上发布的图片了。

4. 发布到微信公众号

微信公众号排版一直是个问题。我甚至一度放弃了公众号创作。作为技术极客,我拒绝了几乎任何不是基于Markdown的排版方案 – 都什么年代了,写个自媒体都是赔钱的,平台还好意思要求我们专门为你们排版?

直到我遇到了mdnice。

它甚至比我自己使用mkdocs-material的排版还要漂亮 – 特别是它对代码的处理部分 – 我超爱她深色主题下的50道阴影!

我现在也超爱写公众号了!不过,什么时候mdnice能实现markdown的admonition语法就更好了。毕竟,这是个信息过载的时代,我们必须用一些留白来缓解密集信息恐惧症,同时用一些闪耀的装饰吸引读者,避免他们走掉。



当然,mdnice也可以直接发到CSDN上。不过,这样会失去定时发布以及自定义标签、选择专栏、定制首图的能力,所以,我宁愿自己登录到CSDN的网站上去编辑,好在,它提供了markdown编辑器,并且能自动处理图片链接。因此,我并不需要一个个地从本地上传,这省了我不少时间。

5. 发布到知乎

如果你使用的是vscode来编辑markdown的话,就可以使用一个名为Zhihu On VSCode的扩展。它支持定时发布(一天以内)、选择专栏,但不支持添加话题,另外,它不能正确处理(去掉)frontmatter。

但是它能处理markdown中的图片链接。这样就省去了我上传图片的时间。它对代码也能很好处理。

不过,知乎的文档格式确实太素净了。

6. 转换为pdf

slidev也可以转换成为pdf。不过,我更喜欢使用vscode的markdown preview enhanced来转换pdf。最终提供转换的是chrome+puppetter。通过在文档的frontmatter中加上适当的标记,就能生成页眉和页脚。

右图就是它导出的一例。

此外,slidev也可以导出pdf。要实现页眉和页脚,需要要定制global-top和global-bottom,一旦定制完成,这种方案似乎更好,毕竟,它是手动分页,我们对页面的控制力更强。

7. 赚点小钱

辛苦辛苦写了博客,想办法赚点钱吧。我们可以通过前面提到的ovrrides方案,让mkdocs-material为每个页面插入一个js脚本。

如果你加入了广告联盟,它们一般就会为你提供一个js脚本,把这个js插入进去就可以了。也可以自己写一个js,把自己要发布的广告,以html片段的形式,放在docs目录下的某一个子目录中,然后通过下面的代码把这些片段插入进来:

function insertAd(minParas, minWords){var links = document.querySelectorAll("a[href*='" + link + "']");if (links.length > 0){console.log("已添加")return}var paras = document.querySelectorAll("article p");var wordCount = 0var paraCount = 0var inserted = 0for (var i = 0; i < paras.length; i++){var p = paras[i];paraCount ++wordCount += p.innerText.lengthif (inserted >= 2){break}if (paraCount >= minParas && wordCount >= minWords) {console.log("find para", p, paraCount, wordCount)p.insertAdjacentHTML("afterend", ad)paraCount = 0wordCount = 0inserted += 1}}if (inserted == 0 & paras.length >= 5){var article = document.getElementsByTagName("article")[0]article.insertAdjacentHTML("beforeend", ad)}
}document$.subscribe(function() {console.log("call in ad")insertAd(40, 4000)
})

这段代码实现了文中和文末插入。只有在文章内容足够长时,才会插入广告。同样地,完整的代码可以在zillionare这个项目下找到。具体位置是docs/overrides/javascripts/course.js。注意不要使用ad.js这样好听好记的名字,它会被adblock这样的浏览器扩展拦截!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/624940.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis配置动态数据源以及参数传递等

Mybatis必知必会 一、Mybatis动态加载数据源 在配置数据源连接时,在企业的真实开发中数据源一般都会写在配置文件中&#xff0c;而不会直接写在mybatis的核心配置文件中 所以,Mybatis为了方便开发人员去动态的获取数据源连接制定了一些特定的标签用于加载这些数据源。 具体做法…

c语言题目之斐波那契数列

文章目录 题目一、什么叫斐波那契数列1&#xff0c;由来2&#xff0c;定义 二、代码编写总结 题目 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、什么叫斐波那契数列 1&#xff0c;由来 在数学历史上&#xff0c;欧洲黑暗时期过后&#xff0c;第…

web3d-three.js场景设计器-sprite广告牌

three.js使用Sprite精灵实现文字或者图片广告牌1.将文字绘制到Canvas&#xff0c;调整对应宽高。2.作为Cavans材质绑定到Sprite3.加载到场景调整适当的scale function createLabel({ text, fontSize, textColor, color, imageUrl }) { return new Promise((resolve, reject) &…

数据结构学习 jz66 构建乘积数组

关键词&#xff1a;数学 双指针 方法一&#xff1a;这个题目我一开始做不知道不能用除法。我做的&#xff1a;[ 用时: 12 m 12 s ] 用了除法 分类讨论 方法二&#xff1a;后来看了提示&#xff0c;双指针&#xff0c;两边各开始乘。 方法三&#xff1a;然后又看了答案可以节…

vue 使用mock模拟数据

vue 使用mock模拟数据 安装依赖 cnpm install axios --save cnpm install mockjs --save-dev cnpm install json5 --save-dev在根目录下&#xff0c;新建一个mock文件&#xff0c;且创建如下文件 utils.js index.js const Mock require(mockjs) const { param2Obj } …

基于selenium的pyse自动化测试框架

介绍&#xff1a; pyse基于selenium&#xff08;webdriver&#xff09;进行了简单的二次封装&#xff0c;比selenium所提供的方法操作更简洁。 特点&#xff1a; 默认使用CSS定位&#xff0c;同时支持多种定位方法&#xff08;id\name\class\link_text\xpath\css&#xff09…

【电脑技巧】Win11关闭自动更新

要想彻底关闭Windows电脑的自动更新&#xff0c;仅仅从系统设置里面选择暂停更新是完全不够用的&#xff0c;只有将windows自动更新的服务关闭掉&#xff0c;才能有效阻止其更新。 关闭win11电脑自动更新的办法&#xff0c;具体操作如下&#xff1a; 1.在winr运行框中输入servi…

vue3中,vue-echarts基本使用(柱状图、饼图、折线图)

注意&#xff1a;vue-echarts在使用前要先安装echarts&#xff0c;不要只安装vue-echarts这一个 echarts官网地址&#xff1a;Apache EChartsApache ECharts&#xff0c;一款基于JavaScript的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xf…

几个Python小案例,爱上Python编程!

Python是一种面向对象的解释型编程语言&#xff0c;源代码与解释器CPython遵守GPL协议&#xff0c;Python语法简洁清晰。 语法简洁清晰&#xff0c;那么我们用少量的Python代码能做哪些有趣的东西&#xff1f;温馨提示&#xff1a;文末必看。 一、画爱心表白 1、图形都是由一…

微软Power Platform使用Canvas app画布应用添加自定义连接器调用外部API展示数据

微软Power Platform使用Power Apps的Canvas app画布应用添加自定义连接器&#xff0c;调用外部API展示数据 目录 微软Power Platform使用Power Apps的Canvas app画布应用添加自定义连接器&#xff0c;调用外部API展示数据1、在Power Apps中找到自定义连接器2、创建一个空白的自…

CentOS7中将MySQL注册为系统服务开机启动

实际生产环境中为了避免重启服务器后所有的服务都手动启动带来的麻烦&#xff0c;建议所有基础服务都设置为开机自动启动。本章节我们主要演示在Centos7中如何将MySQL注册为系统服务&#xff0c;并实现开机自动启动。 ① 手动启动mysql&#xff0c;查看进程信息&#xff0c;复制…

XTuner 微调 课程学习

大语言模型于海量的文本内容上&#xff0c;以无监督和半监督的方式进行训练的 模型微调的目的&#xff1a;使其在具体的使用场景或领域中输出更好的回答 增量预训练——给模型喂新的领域知识&#xff1b; 指令跟随或指令微调—— 基于海量的预训练数据训练出来的模型通常叫做…

SD-WAN解决跨国公司海外工厂网络安全问题

在跨境业务蓬勃发展的今天&#xff0c;越来越多的大型企业出于人力成本的考虑&#xff0c;在人力成本较低的发展中国家建立工厂。然而&#xff0c;传统基于路由器的网络架构已无法为这些跨国企业提供可靠的安全网络。那么&#xff0c;如何解决跨国企业海外工厂的网络难题呢&…

关于Python —— Python教程

开始 Python 是一个易于学习、使用和高效阅读的编程语言。它具有简洁的英文语法&#xff0c;编写更少的代码&#xff0c;让程序员专注于业务逻辑而不是语言本身。 本教程将从深度、专注细节上去理解 Python 这门语言。初学者可以参考此教程理解相应的内容&#xff0c;本教程将…

选中图层为什么不能建立3D模型---模大狮模型网

在Photoshop CC 2021(也就是PS6)中&#xff0c;要将选中的图层转换为3D模型&#xff0c;需要满足以下几个条件&#xff1a; 图层类型支持&#xff1a;只有特定类型的图层可以被转换为3D模型。通常&#xff0c;普通的像素图层、矢量图层和形状图层都可以进行转换。但是&#xff…

软件测试|Python数据可视化神器——pyecharts教程(十二)

使用pyecharts绘制关系网图 简介 关系网图是一种可视化工具&#xff0c;用于展示各个元素之间的关联关系。在数据分析和可视化中&#xff0c;关系网图通常用于展示网络、社交关系、知识图谱等方面的数据。Pyecharts 是一个功能强大的 Python 数据可视化库&#xff0c;可以轻松…

x-cmd pkg | howdoi - 用于替代浏览器搜索编程问题的命令行工具

目录 简介首次用户技术特点竞品和相关作品进一步阅读 简介 howdoi 一个在终端中查找编程问题的命令行工具和 python 库&#xff0c;可用于从堆栈溯源&#xff08;Stack Overflow&#xff09;等编程社区获取搜索问题的答案&#xff0c;并将它们以代码片段的形式显示在命令行中。…

使用记事本修复DBC文件问题V2.0

没想过这种文章也能出第二篇&#xff0c;有个信号没解析出来。 问题现象 回放报文的时候发现需要的信号没有解析出来&#xff0c;报文一共有10个信号&#xff0c;只出来9个。 问题分析 首先就是排查DBC文件&#xff0c;在对应的报文里面有没有这个信号。发现是有的&#xff…

POI-tl 知识整理:整理5 -> 开发一个插件

实现一个插件就是要告诉我们在模板的某个地方用某些数据做某些事情&#xff0c;我们可以通过实现RenderPolicy接口开发自己的插件 模板 1 写一个将标签替换为Hello, world的插件 import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.policy.RenderPolicy; import…

pandas进行数据计算时如何处理空值的问题?

目录 1.数据预览&#xff1a; 2.解决方法 &#xff08;1&#xff09;问题示例 &#xff08;2&#xff09;方法 A.方法一 B.方法二 1.数据预览&#xff1a; 2.解决方法 &#xff08;1&#xff09;问题示例 如下图如果不理睬这些空值的话&#xff0c;计算总分便也会是空值…