迁移SAE wordpress的图片到jekyll

Sep 22, 2012

鉴于曾经友好的SinaAppEngine开始收费了,迫不得已迁出所有文章到Jekyll,将Wordpress文章导出为Markdown的工具不少,比如:

但导出后文章中的图片存储和链接依然在SAE上,万一哪天新浪抽风把欠费应用的图片删除了,我找谁哭去?(其实这么做也是情有可原理所应当可以理解滴)因此必须早点计划迁出图片,主要分解为以下三个步骤:

  1. 下载全站图片
  2. 替换文件夹下转换为Markdown格式的博客 Category 字段
  3. 利用正则表达式替换文章中的图片链接

1. 下载全站图片

我们用到了python脚本下载图片,如果亲没有安装python环境,那(⊙v⊙)对不起我暂时没有其他办法,我有空网上找找然后补上,亲你也可以留言告诉我~

# coding=utf-8

import re
import codecs
import urllib2

# 打开RSS文件读取内容

file = codecs.open('blog.xml', 'r', 'utf-8')
content = file.read()
file.close()

# 用正则从RSS中提取所有图片链接地址
p = re.compile('src="([\w\W]+?)"')
urls = p.findall(content)

# 下载图片文件,并保存到img目录
for url in urls:
    print url
    opener = urllib2.build_opener()
    req = urllib2.Request(url.encode('utf-8'))
    resp = opener.open(req).read()
    newname = url[url.rfind('/')+1:]
    print newname 
    outfile = open('img\\' + newname , 'wb')
    outfile.write(resp)
    outfile.close()

步骤依次为:

  1. 将此文件另存为export.py
  2. 利用wordpress自带导出的工具,将导出的文章(XMl)保存为blog.xml
  3. 在当前目录新建名为img的空文件夹
  4. 执行python export.py

2. 替换文件夹下转换为Markdown格式的博客 `Category` 字段

此步骤是为下一步骤打基础,略过亦可

转换后的markdown文件,由于将yaml中的Category全都转换为了Categories,致使可能会在Categories页面中,虽然文章种类是完全一样的,却被分为两个不同的类别。因此有必要将Categories转换为Category。(不倒过来做的原因是:用rake post命令默认生成的文章yaml文件头采用的是Category,为了写文章方便)

博主利用的是Vim的args命令(神马?你不会用Vim?(⊙o⊙),那就Win下的批量替换IDE帮忙吧,重型工具Eclipse貌似可以……)

参考教程

替换过程如下:

" 标记所有的markdown后缀文件
:args *.markdown
" 替换文章中的Categories为Category
:argdo %s/Categories/Category/eg | update

3. 利用正则表达式替换文章中的图片链接

我们的目的是要将所有 _posts 文件夹下的markdown文件中,所有出现

(http://leiming-wordpress.stor.sinaapp.com/uploads/2012/07/gvim-crash.jpg)

这种结构的字符串,替换为

(assets/images/gvim-crash.jpg)

整个过程很复杂,我们分为多个部分讲解:

3.1 匹配字符串

因为所有 Markdown 文件都是![description](http://image.jpg)的格式,而从SAE中存储的图片都按照![description](http://sae域名1/域名2/../图片名称.图片格式)这种格式存储,我们需要匹配且替换的是http://sae域名1/域名2/../(我在SAE域名是leiming开头)这一部分,在Vim中查询到这一段的命令如下:

/http...leimi[^)]*\/

解释:

  • 第一个/表示Vim的查询指令
  • http表示查询包含http字符的字符串
  • 三个 . 表示匹配三个任意字符(此处为了简单匹配://
  • leimi表示匹配接着的leimi字段
  • [^)]表示匹配非)字符,*表示任意多个非)字符,此处已经完整匹配http://sae域名1/域名2/../图片名称.图片格式
  • \/标志\字符的转义符号,根据正则的贪婪原则,会匹配当前字符串最多的/字符,因此是http://sae域名1/域名2/../字符串

3.2 替换字符串

vim中的替换命令是

:[range]s/pattern/string/[c,e,g,i]

解释:

  • range 指的是范围,1,7 指从第一行至第七行,1,$ 指从第一行至最后一行,也就是整篇文章,也可以 % 代表。
  • % 是目前编辑的文章,# 是前一次编辑的文章。
  • pattern 就是要被替换掉的字串,可以用 regexp 来表示。
  • string 将 pattern 由 string 所取代。
  • c confirm,每次替换前会询问
  • e 不显示 error
  • g global,不询问,整行替换
  • i ignore 不分大小写

因此,要将第一部分匹配的字符串替换为assets/images/,替换命令为:

%s/http...leimi[^)]*\//assets\/images\//gc

3. 多文件替换

参考本文的替换转换为Markdown文件的博客Category字段部分,我们要替换所有markdown后缀的文件中的以上字符串,命令为:

" 标记所有的markdown后缀文件
:args *.markdown
" 替换文章中的http://leiming.../../../为assets/images/
:argdo %s/http...leimi[^)]*\//assets\/images\//gc | update

Update -- 18 Otc 2012

因为采用的是Jekyll Bootstrap 框架,图片存放在根assets/images文件夹下,根目录在该框架下的表示为BASE_PATH,因此修改多文件替换小节的替换命令为:

" 替换文章中的http://leiming.../../../为/assets/images/
:argdo %s/http...leimi[^)]*\//{{ BASE_PATH }}\/assets\/images\//gc | update

到目前为止,本博客所有图片链接均是按照以上方法替换的。


P.S. {{ BASE_PATH }} 在Jekyll中被转义,为了完成本文检索到了解决方法:

For future searchers, there is a way to escape without plugins, use the code below:
To escape {% this %}use:

{{ "{% this " }}%}   

and for tags, to escape {{ this }}use:

{{ "{{ this " }}}}

There is also a jekyll plugin for this which makes it a whole lot easier: https://gist.github.com/1020852

Raw tag for jekyll. Keeps liquid from parsing text betweeen {% raw %} and {% endraw %}

后来发现Github竟然不支持{% raw %}{% endraw %}的表达方式,改之,实际写法如下:

Escape Liquid