博客网(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(“http://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);
}

}

}

10 Responses to “博客网(bokee/blogchina)至WordPress搬家攻略”

  1. maoxs says:

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

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

  2. Ding Feng says:

    Apache的XML-RPC实现的这个问题算Bug吧?应该向他们提啊

  3. Zhang Ling says:

    可能是by design的,只是它的protocol用在WP里不支持。

  4. Ding Feng says:

    建议赶紧去feedburner烧一个feed,国内的feedsky也行。

    省的以后换 feed URL 还烦心通知大家。

  5. Ian Zhou says:

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

  6. Zhang Ling says:

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

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

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

  8. gadzet says:

    Hey there, You’ve done a fantastic job. I will definitely digg it and personally recommend to my friends. I’m sure they’ll be benefited from this site.

  9. Soccer says:

    4. hello there and thank you for your info – I’ve certainly picked up anything new from right here. I did however expertise some technical issues using this website, as I experienced to reload the website lots of times previous to I could get it to load correctly. I had been wondering if your hosting is OK? Not that I am complaining, but slow loading instances times will sometimes affect your placement in google and can damage your high quality score if ads and marketing with Adwords. Anyway I’m adding this RSS to my e-mail and can look out for much more of your respective fascinating content. Ensure that you update this again soon..

  10. 愛鄰搬家 says:

    obviously like your website but you have to take a look at the spelling on several of your posts. Many of them are rife with spelling issues and I to find it very bothersome to tell the reality nevertheless I’ll surely come back again.

Leave a Reply