Categories
Technology

博客网(bokee/blogchina)至WordPress搬家攻略

摘要

Web内容集成曾经是最困难的工作之一,感谢XML/Web services,在Web 2.0的时代终于可以比较容易的实现了。目前绝大部分blog系统都支持两种方式的内容输入:标准的基于Web的方式,即用户登录、发贴;另外就是通过API利用客户端软件发贴。这两种方式可以简单的想象成WebMail和基于SMTP邮件客户端。本文实现了基于半结构化内容抽取和异构XML目标数据的集成。

实现方法

现在常用的Blog API有Blogger API, MetaWeblog API, Movable Type API等,这些API都采用了XML-RPC进行数据包装和传输。 blogchina.com目前仅支持早期的Blogger API 1.0(而且是部分支持),而WP同时支持这三种API。

为了把http://zhangling.blogchina.com 里过去两年的文章完整的搬到新系统中,我首先尝试了用Blogger API去读取blogchina里的文章,但碰到了问题。

用Java开发,我用了Apache的XML-RPC包。经尝试,发现blogchina仅支持blogger.getUserInfoblogger.getTemplateblogger.getUsersBlogs等几个有限的方法,对于关键的抽取文章内容的函数则完全不支持。这意味着所有的内容无法通过编程的方法获得,工作量一下上升了很多。

于是我在浏览器分别打开04-06年的文章列表,用下载工具将页面里所有博客文章进行批量下载(还好这个过程的工作量不是很大),然后在本地磁盘上根据年份和文章分类建立多层子目录,把对应的文章放在不同目录下面。现在的问题变成如何从HTML页面中把文章标题、内容、发贴日期和评论分别抽取出来作为XML-RPC参数发送给WP系统自动建立新文章。仔细研究了这些HTML文件,发现它们都具有相同的结构和布局,仅仅是内容上的变化,其他如布局和风格几乎完全一样。接下来就需要分析HTML代码找到文章标题、内容、日期、评论部分的特征标签以进行内容抽取。比如就标题来讲,所有的标题前都有”diaryTitle”标签;所有发贴日期都符合正则表达式”年\\S*月\\S*日.*星期\\S\\s\\d\\d:\\d\\d”,等等这些信息都对内容的正确提取提供了保证。

根据分析得到的特征标签,写了4个Java class(TitleExtractor, ContentExtractor, DateExtractor和CommentExtractor) 。对300多篇文章进行测试,抽取成功率100%(当然还写了一些字符串处理函数解决一些有变数的字串)。于是,数据源的问题得到的解决。

花费最多时间的倒是对WP的数据写入部分。我用了MetaWeblogAPI,使用XML-RPC中的XmlRpcClient类,构建好参数列表,测试发现中文出现问题。Java程序送出的XML数据包在WP系统上显示为乱码。经调试确认XML-RPC使用的是UTF-8编码,而WP也是配置成UTF-8。在调试多次失败后,我用Ethereal(已经改名成WireShark)捕获了发出去的HTTP数据包,发现Apache的XML-RPC实现把中文字符进行HTML转义,导致WP无法识别。为了验证,我装了Zoundry并尝试发贴,在捕获的HTTP请求包中,Zoundry把“中文标题”四个汉字编码成“\344\270\255\346\226\207\346\240\207\351\242\230”,而且WP正确的接受并成功显示!接下来,我下载了Apache commons codec包,尝试了里面多个编码器,始终没能成功,不得不考虑使用其他Java实现。

最终我找到了合适的包Redstone XML-RPC,它顺利的把我GB2312编码的文章上传到WP上(需要把WP缺省编码改成GB2312),于是剩下的事情就是一个for循环对目录里的所有文件做一次内容提取、参数组装和网络调用。为了简单,我把评论部分附加在正文末尾(因此可以在新博客老帖子的正文部分里看到很多老系统的影子,如黑色的头像:)

结论

虽然一些商业系统开始提供博客搬家服务(如blogbus和讯),由于可用性的限制要实现完整的系统搬家难度还是非常大(我在blogbus尝试10篇文章的搬家未获得成功)。因此,如果懂软件开发的话,自己写点搬家程序会更容易、更便捷。

参考文献

1. Apache XML-RPC: http://ws.apache.org/xmlrpc/
2. WordPress API: http://codex.wordpress.org/XML-RPC_Support
3. Ethereal Bug 894: http://bugs.ethereal.com/bugzilla/show_bug.cgi?id=894
4. PHP和JAVA的XML-RPC中文问题解决办法: http://fanqiang.chinaunix.net/program/php/2005-09-06/3586.shtml

附录(部分代码)

XmlRpcClient client = null;
try {
client = new XmlRpcClient(new URL(“https://www.zhangling.org/blog/xmlrpc.php”), true);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

for (int i = 0; i < files.length; i++) { try { filename = folder.getAbsoluteFile() + "\\" + files[i]; FileInputStream fileInput = new FileInputStream(filename); InputStreamReader reader = new InputStreamReader(fileInput,"GB2312"); BufferedReader bufferReader = new BufferedReader(reader); while (bufferReader.ready()) { content = content + bufferReader.readLine() + "\n"; } } catch (Exception e) { System.err.println(e); }

title = titleExtractor.getTitle(content);
description = contentExtractor.getContent(content)
+ commentExtractor.getComment(content);
datestring = dateExtractor.getDate(content);
content = “”;

Vector v = new Vector();
v.add(“1”);
v.add(“AAAA”);
v.add(“********”);
Hashtable hashtable = new Hashtable();
hashtable.put(“title”, title);
hashtable.put(“description”, description);
Date date = new Date(datestring);
hashtable.put(“dateCreated”, date);
String category[] = new String[1];
category[0] = “技术”;
hashtable.put(“categories”, category);
v.add(hashtable);
v.add(“true”);
try {
Object result = client.invoke(“metaWeblog.newPost”, v);
System.out.println(“received: ” + result);
} catch (Exception e) {
Logger.writeLog(filename + “:” + e);
System.out.println(e);
}

}

}

By Ling Zhang

本人服务于IBM中国软件实验室(上海)。本网页内容仅为个人思想,不代表IBM公司观点。

7 replies on “博客网(bokee/blogchina)至WordPress搬家攻略”

he he… 恭喜,费了这么些力气,看着很酷 🙂

什么时候电信免费让大家都有个域名和网站吧… 到那个时候,估计个人门户就由他们提供了 — 一股脑儿把什么 Blog, Wiki, RSS, eMail, 电子支付/Shopping, searching 等等全都是基于“服务”的方式给 mashup 起来,就不用你这么辛苦了。

我想从MSN Space上面提取日志,但是getRecentPosts只能返回20篇日志的ID。没有全部ID的列表,如何才能把Space上面的内容提取出来呢?163提供这样的迁移功能,说明应该是有办法的吧?

建议看一下MSDN的文章: MetaWeblogAPI and MSN Spaces。里面对getRecentPosts方法的描述是支持post数量的,public struct[] metaWeblog.getRecentPosts(string blogid,
string username,
string password,
int numberOfPosts);

我没验证过,你可以试试。

[…] 在我写了blogChina搬家到WordPress攻略不久,就收到百度工程师的邮件讨论博客搬家的话题。现在看来百度提供的对MSN Space和新浪博客搬家手段可能是完全基于HTML的extract和parsing,而不是blogger API(写入到百度自己的博客系统可以用blogger API或者直接写DB),这就能解释它不仅支持搬自己的家,连别人的家一样搬。来自百度空间的说明基本能证实这一猜测: […]

Leave a Reply

Your email address will not be published. Required fields are marked *

*