博客 – 若水斋 https://blog.werner.wiki Try harder Sat, 10 Nov 2018 09:00:54 +0000 zh-Hans hourly 1 https://wordpress.org/?v=6.8.3 https://blog.werner.wiki/wp-content/uploads/2018/11/cropped-ql1-1-32x32.jpg 博客 – 若水斋 https://blog.werner.wiki 32 32 静态博客如何实现站内搜索 https://blog.werner.wiki/static-blog-search/ https://blog.werner.wiki/static-blog-search/#respond Sat, 12 Aug 2017 08:58:46 +0000 http://blog.werner.wiki/?p=303 许多网站都有站内搜索功能,对于有数据库支持的网站,实现搜索是很简单的事情,而对于静态博客这样没有数据库支持的网站,实现搜索就有点麻烦了。本文总结了静态博客实现站内搜索的几种方法。

1.利用搜索引擎语法

这是最简单的一种,直接利用搜索引擎语法site,如:

    site:blog.werner.wiki 搜索关键词

便是告诉搜索引擎,在网站“blog.werner.wiki”中搜索“搜索关键词”,几乎所有搜索引擎都支持这一语法。实际中如何使用呢?在博客页面中添加如下代码即可(以百度为例):

    <form onsubmit="return baiduWithHttps(this)" action="http://www.baidu.com/baidu" target="_blank">
        <input name="tn" type="hidden" value="SE_zzsearchcode_shhzc78w">
        <input name="si" type="hidden" value="blog.werner.wiki">
        <input name="ct" type="hidden" value="2097152">
        <input type="text"  onfocus="checkHttps" name="word"  size="30">
        <input type="submit" value="百度搜索">
    </form>
    <script src="http://s1.bdstatic.com/r/www/cache/global/js/BaiduHttps_20150714_zhanzhang.js"></script>
    <script>
        function checkHttps () {
            BaiduHttps.useHttps();    
        };
        function baiduWithHttps (formname) {
            var data = BaiduHttps.useHttps();
            if (data.s === 0) {
                return true;
            }
            else {
                formname.action = 'https://www.baidu.com/baidu' + '?ssl_s=1&ssl_c' + data.ssl_code;
                return true;
            }
        };
    </script>

百度支持使用GET参数si来指定网站,需配合&ct=2097152才会生效。上述代码来自百度站长平台,稍有修改,指定了搜索范围限定在网站blog.werner.wiki中,实际运行效果如下:






当然,还可以直接登录百度站内搜索(http://zn.baidu.com/),按照提示生成站内搜索搜索框代码。

此种方法最为简单,但要求搜索引擎对博客内容有所收录。若收录较少,搜索效果会很不太理想。

2.在浏览器端用js实现搜索

这一方法思路来源于《给jekyll添加炫酷简洁的搜索》。原理是在生成静态博客的时候生成一个用于搜索的JSON文件,该文件包含了博客中所有文章的标题和对应的URL。生成这一JSON文件,使用的是类似下面这样的模板:

    {
        "code" : 0 ,
        "data" : [
        {% templatetag openblock %} for post in site.posts {% templatetag closeblock %}
            {
                "title" : "{% templatetag openvariable %} post.title {% templatetag closevariable %}",
                "url" : "{% templatetag openvariable %} post.url {% templatetag closevariable %}"
            }
            {% templatetag openblock %} if not forloop.last {% templatetag closeblock %}
            ,
            {% templatetag openblock %} endif {% templatetag closeblock %}
        {% templatetag openblock %} endfor {% templatetag closeblock %}
        ]
    }

生成的JSON文件点这里可以看到。

在浏览器中,js使用ajax异步加载该JSON文件并解析。当要搜索时,从该JSON文件包含的信息中进行搜索就可以了。考虑到博客内容不是很多,只搜索标题代价就更小了,故而不建索引,不做优化,使用很慢的js进行简单的字符串匹配,也可以获得良好的搜索体验。

李跃东使用这种技术,制作了静态博客Jekyll和hexo的搜索插件。我在自己的博客中使用了他写的插件,双击Ctrl或是点击屏幕右下角的放大镜可以调出搜索框。虽然我既没有用Jekyll也没有用hexo,但原理总是相同的,稍作修改,就可以使用。

该方法的优点是简单可控,缺点是只能搜索标题,最多加上标签、分类,无法进行全文搜索。

3.使用第三方提供的站内搜索服务

简单的说,就是告诉第三方搜索服务提供商自己的博客地址,第三方会排爬虫爬取自己博客的内容,建立索引等待搜索。要搜索时,调用第三方提供的搜索服务即可。提供这种服务的有Swiftype(一个免费限额)、阿里云开放搜索(收费)、微搜索(已挂)。

Swiftype功能强大,可高度定制,提供了很易于使用的API,推荐使用Swiftype。这里有一篇不错的教程:《利用swiftype为hexo添加站内搜索v2.0》,虽然有点过时,但也可供参考。本博客的全文搜索便使用了swiftype。Swiftype的缺点也很明显,便是对中文不太友好。

(2017.09.17更新:Swiftype试用期已过,本博客放弃使用Swiftype实现全文搜索,暂无全文搜索)
(2018.11.10更新:本站已更换为动态博客)

]]>
https://blog.werner.wiki/static-blog-search/feed/ 0
个人博客设计 https://blog.werner.wiki/blog-design/ https://blog.werner.wiki/blog-design/#comments Sat, 01 Jul 2017 06:56:54 +0000 http://blog.werner.wiki/?p=226 我想要怎样的博客?

从读者角度

好看。
这里的好看更多地是从阅读的角度考虑,而不是审美的角度。我希望我的博客易于阅读,字体、大小、排版、高亮、缩进等是合适的,读者不会因为界面而觉得阅读我的博客是困难的。
此外,打开速度也很关键,除了在网速特别慢时,应当能在两三秒内打开博客。

从作者角度

好写。
写作方便,可以很容易地设置分类、标签,添加图片、视频,容易地进行排版。
上传方便,写好博客后可以容易地上传到服务器。
管理方便,可以容易地增删查改博文,备份、迁移博客。

要如何实现想要的博客

好看

字体、字号、颜色等可参考看上去舒服的网页,看看别人怎么设计的。排版、高亮、缩进等完全由html和css控制,当我看到不满意的地方时去修改即可。至于整体界面的美观,我这个完全不懂设计的人,就只能尽人事,听天命了。

将博客部署在国内(coding的pages服务)、用CDN(七牛云)存储图片等静态资源就可获得相当不错的响应时间。当然这是对国内而言,至于身在国外的朋友,就只好稍稍多等待几秒种了。

好写

  • 博文采用markdown写作,方便排版。
  • 调用七牛云API,自动存储图片、视频等静态资源。
  • 用git管理博客,方便上传、备份、迁移。
  • 标签是动态的,随写随加,不需要提前声明。
  • 分类是树状的,化文件目录树为博文分类树,只需将博文保存在某一目录中便设置好了该博文的分类。
  • 博文地址是可设置的,不随分类、标签的改变而改变。

总体设计

Wblog

为保证访问速度,博客只好部署在国内;避免域名备案,博客只能部署在pages服务中。

因此,我需要的是一个类似Jekyll和hexo这样的静态博客生成工具。Jekyll不能满足我的需求,hexo我没有用过,也暂时不打算去学习如何使用它(听说是hexo是台湾的小伙开发的)。所以我决定自己实现一个,就起名叫Wblog好了。

Wblog的工作是生成静态博客,具体地讲,是将markdown格式的博文渲染为html,处理好分类和标签。

Wmedia

Wblog只负责生成静态博客,不干其他事情。我还需要一个工具来管理图片、视频等静态资源。Wmedia的工作是自动上传静态资源到七牛云,获取外链,并自动替换静态博客中的静态资源链接为七牛云外链。

详细设计

Wblog

Wblog的实现是一个名为wblog.py的Python脚本,其作用是读取博客内容,进行markdown渲染和模板编译,生成静态博客。

准备文件

首先介绍必须的文件、目录:

wblog.conf          //配置文件
index.md            //主页
layouts/            //模板
  -- tag.tpl        //标签
  -- post.tpl       //文章
  -- cate.tpl       //分类
posts/              //博文目录树

非必须的:

static              //存放静态资源文件

运行wblog.py会生成的:

sites/              //生成的静态网站
.compilelog         //记录了渲染编译的历史

博文以makrdown写作,在下文中称为markdown文件,该文件应当以.md结尾。该文件有head部分和body部分。body部分是以markdown语法写作的博客正文,head部分是关于该博客的信息。一个简单的markdown文件如下所示:

---
layout: post.tpl
url : firstmarkdown
title: 我的第一个makrdown文件
date: 2017-06-30
tags: ['置顶', '开始']
---

## HELLO WORLD

这是我的第一个markdown文件,请多多关照。

—和—之间的部分便是head部,该部分是由键值对组成,键是以字母打头,字母或数字组成的词(和通常的编程语言的变量名要求一样),键值之间用:隔开,值可以是字符串、整数、列表等。列表中的字符串必须用引号包围,其余的字符串可以不用引号包围。

wblog.conf文件中也是以:分割的键值对,规则同markdown文件的头部。

工作过程

下面来说说wblog.py的工作过程,如下图所示:

首先,wblog.py读取wblog.conf文件,解析其中的键值对,保存为字典site。

接着,wblog.py会递归遍历posts目录,读其中的markdown文件,解析出它的head和body,将head转换为字典,并添加一些键值,渲染body为html文件,并保存在sites目录中,然后以渲染出的html文件为模板,以head和site为参数,进行编译,用编译结果替换html文件,生成最终html文件。若遇到.html或.htm文件,直接复制到sits目录中,以site为参数进行编译。

head中至少有以下几个键:

  • url 字符串,访问该url可访问该博文
  • size 整数,该博文字数
  • date 日期,该博客的写作日期

若markdown的头部缺少url字段,则会自动生成一个随机数作为该博文的url,并将url写会到makrdown文件中。若markdown的头部缺少date字段,则会以当前日期作为该博客的写作日期,注意date字段不会自动写回。

在遍历posts目录的同时,会在内存中根据posts的目录树构建出一颗分类树,树根的变量名是root_cate,根据markdown文件的头部信息中的tags构建出一个标签列表,列表的变量名是tags。

分类树是一颗树,由嵌套的字典表示,每个分类是一个字典,其键值如下:

  • name 字符串,该分类的名字
  • url 字符串,访问该url可到该分类页面
  • subcate 列表,该分类的子分类,子分类也是字典
  • posts 列表,直接属于该分类的博文列表
  • number 整数,直接属于该分类的博文篇数

标签列表中的每个元素是一个标签,标签也是字典,其键值如下:

  • name 字符串,该标签的名字
  • url 字符串,访问该url可到该标签页面
  • posts 列表,其中成员为post
  • number 整数,该标签下博文篇数

在递归遍历posts目录的同时,会在sites/categories目录中生成和posts目录具有相同结构的目录树。在遍历完posts目录后,内存中已经有了分类树,然后就会遍历sites/categories目录,在这个目录中的每个子目录(包括它自己)中都生成一个index.html文件,这个文件是以layouts/cate.tpl为模板、以目录对应的分类字典和site为参数生成的,用分类的url,可以直接访问这个文件。

接着,wblog.py会读取layouts/tag.tpl,以此作为模板,遍历标签列表,以每一个标签和site为参数编译此模板,生成一些列网页文件,保存在sites/tags目录中,这些网页文件用标签的url可以访问。

之后,还会遍历当前目录,遇到markdwon文件则渲染编译、遇到html或htm文件则只编译,将这些编译结果也保存到sites目录中。

最后,wblog.py会复制static目录到sites目录中。这样,便完成了静态博客生成。

一个问题便是若每次运行都要渲染、编译全部markdown文件岂不是会很慢?确实是这样的,解决方法便是每次渲染、编译后记录该文件的hash值,下次再遇到该文件,根据hash值判断该文件是否改变,若没有改变,则不需要再次处理。

但是存在这样的情况,markdown文件没有改变,渲染、编译结果却是不同的,这是由于wblog.conf或layouts中的模板改变了。因此,一味地跳过没有改变的markdown文件是不合适的。所以,引入参数-a,a的含义的all,若有此参数,则无论markdown文件是否改变,都再重新处理。

模板

模板语言使用django的那一套,灵活,强大。当然主要原因是我对django比较熟悉。

全部模板都可使用的变量有:

  • site
  • tags
  • root_cate

不建议在post.tpl等博文模板中使用tags和root_cate,因为posts未遍历结束,tags和root_cate中信息可能不全。

此外,三个必须的模板中各有一个特殊的变量:

  • tag.tpl tag 字典,当前标签
  • post.tpl post 字典,当前博文
  • cate.tpl cate 字典,当前分类

这几个模板都会被多次使用,每次使用会传入不同的参数,生成不同的结果。

post.tpl是markdown文件默认的模板,也可在head中用layout来指定模板。

另外,在渲染markdown为html后,会用“{% block post %}”和“{% endblock %}”包围html,并在其前添加“{% extends “模板名” %}”。所以,用layout指定的模板中应该包含“{% block post%}{% endblock %}”。

Wmedia

直接将图片这样的静态资源存储在github、coding的仓库中不是不行,但是不好,有更好的方式,即将图片存储在七牛云这样的CDN。

若是手动保存图片至七牛云,则需要经过以下几步:

  1. 打开浏览器
  2. 打开七牛云网站
  3. 登录
  4. 进入存储存储,选择存储空间
  5. 上传图片
  6. 复制外链
  7. 将外链写在.md文件中

除了麻烦外,这样做还有以下三点不足:

  1. 写文章时若需要插入图片,则必须处于联网状态
  2. md文件中写入长长的外链很不美观
  3. 虽然可以备份图片,但图片链接仅仅有指向七牛云中的那一份,缺乏有效备份

所以需要一个工具来自动的上传图片,获取并替换链接。

写作时,在markdown中,图片用

../../static/img/iampic.jpg

来引用,生成的HTML中图片链接也是

../../static/img/iampic.jpg

生成静态博客完毕后,再运行Wmedia,它只作用于sites目录,会遍历sites目录中的所有文件,匹配src中从static/img目录引用资源的链接,上传资源并将链接替换为从七牛云返回的资源外链。

上传文件时调用七牛云API,官方给出了示例代码,很容易实现。关键在于要准确区分哪些文件没有上传过,哪些文件已经上传过,不需要再次上传,哪些文件发生了变化,需要再次上传。

维护一个上传数据库,数据库中记录结构如下:

本地文件路径:hash:url

每上传一个文件,就在该数据库中添加一条记录。
再次运行时,读到一个文件,先在数据库中查找,若找到,则比较hash,若一致,则不用再上传,直接返回url,若不一致,则更新hash,重新上传,更新url。若在数据库中未找不到对应记录,则上传并添加新记录。

虽然名叫做数据库,但实际上用一个文件就可以了。上传信息将保存在文件.update中。

前端设计

其实也谈不上设计了,只是最普通不过的网页布局。顶部是菜单栏,底部是版权声明栏,中间分为左右两部分,左半部分展示博文内容,右半部分是我的头像和友情链接等常驻信息。屏幕较小时隐藏右半部分。

菜单共有以下几个:

  • 主页
  • 分类
  • 标签
  • 归档
  • 微言
  • 读书
  • 关于

一直没想好主页要怎么设计,就干脆把这篇文章作为主页。
分类是一个下拉菜单,其子菜单便是一级子分类。
点击标签菜单可以看到所有标签,按文章数量从高到低排序。
点击归档可以看到所有文章,按发表时间从新到旧排序。
微言和读书以及关于都和以前的博客一样,相当于三个独立页面。

部署使用

安装依赖:

    sudo pip install Django==1.8
    sudo pip install markdown
    sudo pip install Pygments
    sudo pip install qiniu

在coding上创建两个项目,一个私有一个公开。
私有项目用于存放生成前的博客,公开项目用于存放生后的博客。
在公开项目中创建pages,用于博客访问。

在博客主目录中运行git init,并设置其远程仓库为coding上的私有项目。添加.gitignore文件,内容为:

    *~
    sites

忽略临时文件以及生成的静态博客。

在sites目录中运行git init,并设置其远程仓库为coding上的公开项目。添加.gitignore文件,内容为:

    *~
    static/img

忽略临时文件以及static/img中的文件,static/img中的文件是要保存到七牛云这样的CDN上的,
且在私有项目中已有备份,故不再上传。

这样部署,便确保了每一个文件至少在两个不同的地方有备份。若自己本地磁盘上的博客文件损坏,
只需git clone下私有项目即可;若coding上的文件损坏,只需重新git push下即可;
若七牛云中文件损坏,只需删除.update文件重新运行python wmedia.py即可。

修改好博客后,先用命令

  python wblog.py

来生成静态博客。生成完毕后,进入sites目录,运行命令

  python -m SimpleHTTPServer

在浏览器中访问:http://127.0.0.1:8000/,就可以看到本地运行的博客了。

修改满意后,运行命令

    python wblog.py
    python wmedia.py
    git add -A
    git commit -m'自动提交'
    git push
    cd sites
    git add -A
    git commit -m'自动提交'
    git push

来将博客推送到远程仓库。命令有点多,一条一条敲很不方便,故写成一个名为auto.sh的脚本:

  if [ "$#" -ge "1" ]  
  then
      python wblog.py
      python wmedia.py
      git add -A
      git commit -m'自动提交'
      git push
      cd sites
      git add -A
      git commit -m'自动提交'
      git push
  else
      python wblog.py
      cd sites
      python -m SimpleHTTPServer
  fi

当auto.sh没有参数时,执行if的else分支中的命令,有任何参数时,执行if的then分支中的命令。

如果你也想使用Wblog,请联系我:me@werner.wiki

]]>
https://blog.werner.wiki/blog-design/feed/ 2
Hello World! https://blog.werner.wiki/hello-world/ https://blog.werner.wiki/hello-world/#respond Wed, 17 Feb 2016 03:30:38 +0000 http://blog.werner.wiki/?p=62 这是本博客的第一篇文章,欢迎访问。

以前在使用网易博客的时候,一段题为“说明:为什么要开通个人博客?”的话:

其一:在学习的过程中难免需要在网上搜集资料。在搜索后,往往可以看到有很多博客文章,其中正包含着我所需要的内容,给了我很大的帮助。所以我就想将自己学习过程中的经验、技巧、想法等内容记录在这个公开的平台上,“闻道有先后”,希望可以帮助到后来者。

其二:“吾生也有涯,而知也无涯”,人又是容易遗忘的动物。将学习的过程记录在这,等到自己需要某些学过的知识却回忆不起来时,便可以来这里看看。

标注的日期是2015年6月30日,18:56:52。当初只是零星地写了几篇文章,便放弃了。一方面是不喜欢网易博客复杂的功能、过多的推送,但主要还是由于我自己不够勤奋,没能热情地写作。半年后,学会了更多的知识,可以在一定程度上脱离冗杂的平台,自力更生,于是便有了这个博客,特意购买了域名,以激励自己认真地写博客。

]]>
https://blog.werner.wiki/hello-world/feed/ 0