搭建自己的静态 Wiki 站点(Vimwiki+Pages)

以前整理自己的东西都是用印象笔记,槽点太多了,比如只支持1级目录,列表页不友好等,整理起来很不方便。最近发现了 Vimwiki 这个好东西,于是想出另一种策略:

  1. 用 Vim 撰写个人 wiki (Vim 是我最喜欢的编辑器,第二喜欢的是 WordPress 后台编辑器)
  2. 用 git 追踪变更记录,每次写入的时候自动追加 commit 信息 (这样自己完全可以不用关心备份了)
  3. 用 Github pages 来托管 html (静态网站托管无比简单,写 wiki 就是为了方便查阅,如果再耗费很多精力去运维就得不偿失了)

1.新的 Github 账户

我的 Github 账号的 Pages 已经托管了一些小玩意,所以另申请了一个账号,专门用来记录 wiki。用新账号新建一个 Pages 并将主账号加入到合作者,这样 key、邮箱都不用再另外配置了。

自己邀请自己还有点奇怪

然后新账号就可以丢掉了,以后全部用自己的主账号操作。

接下来配置 Vim 和 Vimwiki。

2.安装和配置

毕竟是一个很老的项目,提供了各种 Vim 包管理工具的安装方式。可以通过 Readme 的信息选择你喜欢的方式安装。

然后 clone 下来我的 Pages 仓库,创建 wiki 文件夹存放源文件,创建 html 文件夹来保存生成的 html 文件。

.vimrc 中加入如下配置,设置 Vimwiki 的路径:

然后在 Vim 中按下 <leader>ww 就可以看到一个新创建好的 index.wiki Buffer 了。

随便写点什么保存,然后在 Vim 中执行 :Vimwiki2HTML 就可以将 wiki 文件编译成 html。然后将其 push 到 Github 上,就可以在线上看到这个页面了。

可以写一个 Makefile 自动化发布的过程。

这样只要运行 make publish 命令,就会自动构建最新的 Wiki 并发布到 Pages 上。

3.自定义域名

静态托管简直太爽,我相信 Pages 在我有生之年不会倒闭,但是为了以防万一,还是使用自己的域名,这样将来万一要切换,也会很方便,直接改下 DNS 解析位置就好了。首先添加一个 CNAME 文件让 Pages 跳转到我自己的域名: echo "wiki.kawabangga.com" > CNAME 然后 PUSH 上去就可以了。然后再到自己的域名服务商那里添加一个 CNAME 指向 laixintao-wikibot.github.io 。等解析生效就可以通过 wiki.kawabangga.com 访问了。

到这里就差不多搭建起来了,接下来就是熟悉一下 WIKI 的语法、学下 Vimwiki 的快捷键使用。另外默认的 template 太丑了,就是一个基本的 html,有时间的话还要在网上找找有没有漂亮点的 theme。

 

参考资料:

  1. 使用 Vimwiki + git 做知识管理
  2. http://kwiki.github.io/tips/vim/vimwiki-guide.html
 

Vim文件编码处理和重新打开乱码文件

Vim 中有两个与编码有关的变量,如果理解了基本就不会再为编码问题头疼了。

  • encoding :Vim 内部编码,例如 buffer、寄存器、文本等。这个值一般用户不要设置,另外打开 Vim 之后再设置这个值也是没有意义的。大家可以将这个值看作是 Vim 程序自己的变量,如果在工作中遇到文件的编码问题,和 encoding 这个变量是万万没有关系的。
  • fileencoding :顾名思义了,就是文件的编码。

此外还有一个值,叫 fileencodings 是个复数。一般我们将这个值在 vimrc 中设置,Vim 打开一个文件的时候回根据 fileencodings 里面设置的顺序来猜测文件的编码。比如这样设置:

那么有时候 Vim 猜错了,打开的文件显示乱码怎么办呢?(ps:通常 Vim 打开文件的时候乱码是因为你的 fileencodings 里面没有写某个编码,所以 Vim 没有猜对。例如从上面的设置中删掉 gb18030 ,那么打开这种编码的文件的时候你会发现 fileencoding 的值是 latin1 ,而文件的显示是乱码)

这时候你可能想到设置 fileencoding 的值,但是此时我们的文件已经打开了,你设置后会发现 Vim buffer 的状态变成了 Edited 。而文件依然显示乱码,没有变化。具体的原因后文会详细解释。

正确的做法是以特定编码重新打开文件,例如在 Vim 中使用重新打开命令 :e ++enc=gb2312 ,其中 ++enc 是一个选项,可以指定使用的编码。打开后你会发现 Vim 按照你指定的形式打开了文件,但是文件变成了 readonly 状态,如果要修改,设置 :set noreadonly 就好。

其实原理有点像 Python 里面有人提出的三明治模型

Python 在从流(例如网络, 文件 I/O 的时候),拿到的是 bytes ,通过 decode() 变成 str 而 Vim 在读入一个文件的时候,根据 fileencoding (用户设置的或者通过 fileencodings 猜测,将其转换成内部 encoding 的编码方式。

Python 在写入文件的时候,用 encode() 变成 bytes 再写。而 Vim 从 buffer 写到文件的时候,也是将数据从内部的 encoding 转换成 fileencoding 再写入。

这也就解释了为什么乱码的时候在 Vim 中修改 fileencoding 没什么卵用。

因为在打开文件之后设置 fileencoding 的值不会改变已经载入到 Vim buffer 中的数据,此时的数据已经是转换完成了的,这个设置只会改变写入的时候使用目前的 fileencoding 来写入,所以总结起来就是“打开文件使用了一个编码,写入文件的时候使用了另一个编码”。

而对乱码正确的需求应该是:我想要以特定的编码形式打开这个文件。

参考:

  1. help :edit
  2. help fileencoding
  3. help ++enc
  4. VIM 文件编码识别与乱码处理
 

无价的价值

今天看到一则杂闻,摘抄简略如下:

假离婚变真离婚,真相原来这般残酷!在北京工作的小琴(化名)近日在网上发帖讲述自己的遭遇:“身为北大博士后的丈夫,以孩子户口为由骗我离婚,之后不肯复婚了,还很快跟女同事结婚,并且新欢已怀孕。”如今,她只有一个想法,就是要讨个说法!

看到之后,觉得其实有很多东西,如果你重视它,它就有自己的价值;如果觉得无所谓,那么它就是真的没什么价值。”无价“来表达这个意思最合适了。听起来有点像宗教,算是有点像吧,但是今天不谈宗教。我最近有这种想法主要还是来源游戏。

最近主要在玩《血源诅咒》和在手机上玩一个老游戏,《This War of Mine》。发现很多游戏有这么一个特点:如果有一天某个地方卡了很久打不过去,或者某个游戏玩的时间长了,你可能把手柄一扔,觉得“算了吧,这游戏也就这样,同样的技巧打打杀杀,找到 Boss 弱点慢慢磨最后过关”。基本上这是我玩腻大多数游戏的原因。一旦有这种想法了,再去玩就觉得真没意思,里面的怪物对我来说毫无吸引力,即使出现新的怪物也没有精神。相反,没有这种想法的时候,就觉得自己真的在这里世界里,享受跟怪物周旋的过程。有趣和无趣,有意义和没有意义,就在一念之间。

上面这一段好像很难把我在自己的意思表达清楚。《This War of Mine》这个游戏更典型一些。这是个战争生存游戏,你可以去各种地方搜刮物资,也会遇到各种各样的人。你需要经常做出抉择:比如在一个寂静的小屋里有一对老人物资非常丰富,抢了他们的东西他们就会死去。你可以把它当成一个纯粹的游戏来玩,按照收益的高低做出各种决定;也可以将自己代入到这个游戏中,依照自己的道德标准做决定。如果你真的认为是自己在这个战争中,那么游戏里面的人不再是只会说两句话的 NPC ,而是战争下受难的苍生。当然了,如果不管自己的道德观念,只是玩这个游戏的话,也可以体验到游戏的乐趣。

回到开头提到的这条新闻。世界上就是有这么两种人:一种人会计算收益行事,假离婚能买到房子,那就假离婚;一种人注重仪式,认为婚姻是一辈子的大事,必须认真看待。这里面有对错吗?我觉得没有。现在的社会后一种人已经很少了。新闻里的这个女人,只能怪自己笨加上运气不好吧。

现在的生活节奏太快了,赚再多的钱,买第二套房子,第三套,意义是什么呢?很少有人会再纠结这个问题了吧。在《血源诅咒》里面击杀怪物,获得血之回响(这个游戏中击杀怪物获得的经验),升级自己的属性,这意义是什么呢?这个游戏中并不需要那么高的属性就可以通关,属性的加成作用还是很小的,其实主要是看技术。我们的人生也一样啊!我们并不需要那么多钱就可以生活的很好。但是很多人都会没日没夜地拼命赚钱,游戏里也有玩家一遍又一遍地刷着血之回响。可能到了最后,这些玩家会发现自己所有的属性加到了最高,可以毫无压力地击杀 Boss ,回头来看却发现自己花费了如此多的时间在经验上,这么多的时间,没有在享受游戏!这样的玩家是不是和游戏中的“加斯科因”神父一样,沉迷于狩猎而迷失了自我?

那么人生的意义是什么呢?游戏的意义是什么?

可能这个问题本来就没有答案吧。如果你认认真真地玩这个游戏,可能会在游戏中体会到更多的乐趣,会体会到喜怒哀乐,会觉得游戏中的小女孩、神父、教堂的女人都是实实在在的人物,可能会为他们高兴、伤心或叹息吧!在生活中,如果认为仪式是一件重要的事情,认为家庭、婚姻是无法用金钱衡量的东西,如果有自己深爱的事业或兴趣,那么也可能体会到更多生活的乐趣吧!

这对我们有什么启发意义呢?好像并没有什么,可能这些都是我的胡思乱想。不过我以前有过一次经历,通过作弊器将某个游戏的经验直接升到最高,缺发现我马上对这个游戏失去了兴趣,觉得什么都有了,什么也都没啥意思。如果我在血源诅咒中有大量的血之回响,可能我也会觉得这个游戏没意思吧。

 

爬虫如何判断一个页面更新了?

一个网页距离爬虫上次访问是否更新了,这个是重要但是又非常难判断的问题。如果只是一次性抓取来一些数据来用,那这个问题无关紧要。但是通常情况下,我们抓到一个页面之后,还需要知道这个页面的后续变化,如果内容变了,必须再抓一次,让我们数据库保存的数据保持与目标页面的同步。

目前来说,我们使用的方法是定期(例如每天深夜)抓取。将所有的爬虫脚本用 crontab 的方式管理。这样是无状态的,我不需要之后目标网站到底更新了没有,定期抓一次保持同步就可以。

这样的问题就是浪费资源。无论对方更新没有,你都要像个傻瓜一样执行一遍同样的任务。如果能先知道这个网页是否更新了数据,就能停止后续的抓取工作,节省一些带宽和计算资源。如果你要监控1千个网站,那么每天去抓一整遍1000个网站所有页面,和每天抓取1000个网站更新的内容,区别是巨大的。

其实吧,这个是长久以来的痛点。早在远古时代,大家都耿直地在自己的博客上更新内容,订阅其他人的博客(而不必每天打开一下所有的页面)就成了一个硬性的需求,所以就有了RSS。可惜的是,并不是所有网站都提供RSS源的,这个功能指望不上。

在网上查了一下,最后找到两种思路,都不是非常完美。第一种基于 HTTP 协议,第二种基于网页内容。

1.使用HTTP状态码判断

HTTP状态码规定了304字段,在 Chrome 控制台可以看到很多 js css 文件都是 304 状态码的。这种方法优点是节省资源;缺点是极不可靠,因为并不是所有的服务器都会返回 304 状态码,况且现在很多网站是单页应用,动态加载。 index.html 是一直不会变的。知乎上有位同学描述了具体的做法,我直接抄过来了。

  1. 第一次先请求某个网页,抓取到本地,假设文件名为 a.html。这时文件系统有个文件的修改时间。
  2. 第二次访问网页,如果发现本地已经有了 a.html,则向服务器发送一个 If-Modified-Since 的请求。 把 a.html 的修改时间写到请求里。
  3. 如果网页更新了,服务器会返回一个 200 的应答,这时就重新抓取网页,更新本地文件。
  4. 如果网页没有更新,服务器会返回一个304的应答。这时就不需要更新文件了。

这种方法的弊端和 RSS 一样,你不能指望所有的网站都正确实现了 HTTP 。比较靠谱的、但是有些麻烦的是根据网页内容判断。

2.基于网页内容的比较

由于要纵向比较网页内容,所以不免这个思路是“有状态的”,需要数据库或类似的服务保存历史网页。

历史网页的对比也是个难点。有些网页有展示“访问量”,“当前时间”的内容。这些东西的变化不应该算作“网页更新了”。比较靠谱的是监控页面的某个 xpath ,而不是网页全部。不靠谱的是采用各种判断条件花式决定“网页更新没有”。比如:

  • 网页最大面试的 block 是否更新
  • 对网页进行截图,对比截图的相似度
  • diff一下相似率

还发现了一个“网页指纹+海明距离”的算法,大体看了一下这个算法貌似是判断海量网页中两个网页是不是相同的事情。比如同一条新闻被两个网站转载,两个网站 html 完全不一样,但是新闻的内容文字一模一样,采用 simhash 算距离就可以认为这两个网页说的是一件事(我不太确定)。

这方面有一些现成的监控服务,例如:

  1. https://sleepingspider.com/
  2. https://distill.io/
  3. 网页兵 page monitor
  4. 分秒数据

 

我自己也尝试写一个,打算用 webhook 的方式发送通知,用 Celery 固定频率访问网页。然后用自己的想象力写一个判断是否更新的决策。项目进度在这里:https://github.com/laixintao/page-watcher  (最后也可能编程一个坑)

 

Vim缩进有关的设置总结

  1. tabstop : 一个tab等于多少个空格,当 expandtab的情况下,会影响在插入模式下按下<tab>键输入的空格,以及真正的 \t 用多少个空格显示;当在 noexpandtab 的情况下,只会影响 \t 显示多少个空格(因为插入模式下按 <tab> 将会输入一个字符 \t )
  2. expandtab :设为真,在插入模式下按<tab>会插入空格,用>缩进也会用空格空出来;如果设置为假noexpandtab,那么插入模式下按<tab>就是输入\t,用>缩进的结果也是在行前插入\t
  3. softtabstop :按下 <tab> 将补出多少个空格。在 noexpandtab 的状态下,实际补出的是 \t 和空格的组合。所以这个选项非常奇葩,比如此时 tabstop=4 softtabstop=6 ,那么按下 <tab> 将会出现一个 \t 两个空格。
  4. shiftwidth :使用 >> << 或 == 来缩进代码的时候补出的空格数。这个值也会影响 autoindent 自动缩进的值。

Vim的官方文档给出了4种常用的设置:

作为一个 Pythoner ,\t 和空格混用的应该拉出去烧死。所以我推荐的配置是:

然后对于下列文件类型,4个空格太宽了,看起来比较累,可以换成2个空格。

相关参考: https://stackoverflow.com/questions/30408178/indenting-after-newline-following-new-indent-level-vim

 

最近硅谷第五季回归了,不知道大家记得不记得 Hendricks 和女朋友因为tab还是空格吵架的事情,我觉得 Hendricks 是对的啊,如果用 \t ,那么可能不同的IDE对 \t 可以更本地化地对齐一些,但是明显四个SPACE更稳啊,如果混用,到时候你咋看出来空的地方是 \t 哪个地方是SPACE呢。以前碰到很多下载下来代码打开,对齐乱七八糟的情况,简直十恶不赦。