本博客在很早以前就启用了多说社交评论功能,这么多年虽然不能说很完美吧,但在同类产品中多说已经算是做的相当不错的了。但从大概这周1开始,多说后台开始出现大量垃圾评论,其量之大真是这些年从来没有过的!(之前虽然也有垃圾评论,但也就极偶尔的1-2条而已,而且看了下网站访问统计,也没有大量的PV,明显是直接刷的多说评论接口),最后实在无法忍受,开启了所有评论的审核机制,即使这样,后台还是会定时出现大量的新垃圾评论。去多说官方论坛看了下,发现也没人提,官方也没反应,而且看论坛上的消息貌似是已经放弃治疗了,果不其然在前天,多说官方放出了即将关闭多说项目的通知:http://dev.duoshuo.com/threads/58d1169ae293b89a20c57241。其实之前也曾一度想从多说转移到其他的社交评论系统,但几番对比后,发现多说还是有较绝对的优势的,这回却是不得不搬家了!
大致扫了一眼wordpress的社会化评论系统,国内的友言、灯鹭什么的看起来也半死不活的(查灯鹭时看到个貌似是插件作者自己搞的新版本叫”Wordpress连接微博”:http://blogqun.com/doc/wp-connect.html,看着是积极开发的状态,功能也比较丰富,但就是要至少199RMB的使用费,而且看了下前端UI不是我喜欢的风格,后端又有诸多要求,于是就不作考虑了),剩下的就是搜狐的畅言和美帝的disqus,本来想直接disqus得了,功能和前端样式都是我喜欢的类型(本地评论也能顺利导入,虽然丢了头像等信息),但遗憾的是一方面近来disqus被墙的死死的,更重要的是另一方面disqus连接的社交系统都是fb,twitter等,也许以后哪天我决定写全英文博客时才更适合用吧…于是,也排除掉了!
所以,基本上,转移阵地的目标就是搜狐畅言了,看了下畅言的更新频率也还可以,而且功能也算丰富,尤其喜欢那个小印章功能!注册畅言账号后,问题就来了:怎么把现有的评论内容全部迁移过去呢?
wp后台装上畅言的插件后,倒是有同步本地评论的功能,满心欢喜的点了一下,然后插件也痛快的给我报了个错:
同步失败:import to changyan error!
再看畅言后台上的数据导入部分,选项倒是不少,畅言、友言、多说的json数据都可以(官方说明有个很奇葩的“1、从畅言导出的评论格式不支持直接导入畅言”,不明觉厉…),看到有多说,于是直接从多说后台导出一份“包含文章数据+包含评论数据”的zip,上传畅言,又爽快的给我报了个忘记什么内容的错!不过这是刚开始被垃圾评论刷屏的时候试的,后来多说放出要关项目消息之后,再上友言后台,发现选多说json时直接弹出了个小提示框(呵呵,反应够快的),解释了下导入要点(看了以后还是没明白那个二级域名是干啥的!),然后又试了下导入多说导出的json,好,这次不再爽快的报错了,看了下貌似也导入成功了,到后台按提示找到导入的评论一看,我勒个去的!丢了不少评论不说,评论内的回复引用关系也没导入成功,于是果断删除刚导入的“脏数据”,自己动手写个转换工具吧。
仔细看了下畅言文档中的json数据格式(这点还是要给个赞的,文档比较全面规范),决定不从多说数据入手,而改用wordpress本身的导出数据xml(当然,在这之前需要把多说的评论同步回本地,默认情况下多说是会自动回写wp本地评论的),经过几次试验,写了个基本能用的python脚本,不能说多完美转换吧,反正该有的用户名、评论内容、回复引用等都有了。
脚本如下(python 3.x版):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | import sys import time import re import xml.etree.cElementTree as ET # 处理中文为转义\u格式并替换可能存在的双引号 def unicode_escape(raw_string): return str (raw_string.encode( 'unicode_escape' )).replace( "\\\\", " \\ ")[2:-1].replace(" \" ", " \\\"") # 清除所有html标签 def clean_html(raw_html): cleanr = re. compile ( '<.*?>' ) cleantext = re.sub(cleanr, '', raw_html) #return unicode_escape(cleantext.replace('\n', '').replace('\r', '')) return unicode_escape(cleantext) # 获取wordpress导出xml中的ns def parse_and_get_ns( file ): events = "start" , "start-ns" root = None ns = {} for event, elem in ET.iterparse( file , events): if event = = "start-ns" : if elem[ 0 ] in ns and ns[elem[ 0 ]] ! = elem[ 1 ]: # NOTE: It is perfectly valid to have the same prefix refer # to different URI namespaces in different parts of the # document. This exception serves as a reminder that this # solution is not robust. Use at your own peril. raise KeyError( "Duplicate prefix with different URI found." ) ns[elem[ 0 ]] = "{%s}" % elem[ 1 ] elif event = = "start" : if root is None : root = elem return ET.ElementTree(root), ns # 默认源xml wp_xml = "D:\\blogc\\k-resblog.wordpress.2017-03-22.xml" # 可能存在的第一参数作为源 if len (sys.argv)> 2 : wp_xml = sys.argv[ 1 ] # print重定向为输出json文件 sys.stdout = open (wp_xml + ".json" , "w" ) #tree = ET.ElementTree(file=wp_xml) tree, ns = parse_and_get_ns(wp_xml) root = tree.getroot() wp_users = [] # 评论id起始偏移,可供需要修复错误时重复导入用 cmt_offset = 1000 # 用户唯一id起始偏移 userid_offset = 1000 # 遍历所有有评论的post挨个处理 for elem in root. iter (tag = "item" ): post_type = elem.find(ns[ "wp" ] + "post_type" ) post_comments = elem.findall(ns[ "wp" ] + "comment" ) if len (post_comments)> 0 and post_type.text = = "post" or post_type.text = = "page" : print ( "{\"title\":\"" + unicode_escape(elem.find( "title" ).text) + "\"," , end = "") print ( "\"url\":\"" + elem.find( "link" ).text + "\"," , end = "") # 这个时间畅言貌似并没有处理时区问题,也许应该用GMT+8的本地时间 pub_date_gmt_str = elem.find(ns[ "wp" ] + "post_date_gmt" ).text pub_timestamp = time.mktime(time.strptime(pub_date_gmt_str, '%Y-%m-%d %H:%M:%S' )) print ( "\"ttime\":\"" + str ( int (pub_timestamp * 1000 )) + "\"," , end = "") print ( "\"sourceid\":\"" + elem.find(ns[ "wp" ] + "post_id" ).text + "\"," , end = "") print ( "\"parentid\":\"0\",\"categoryid\":\"\",\"ownerid\":\"\",\"metadata\":\"\"," , end = "") print ( "\"comments\":[" , end = "") for post_comm in post_comments: cmt_id = int (post_comm.find(ns[ "wp" ] + "comment_id" ).text) + cmt_offset print ( "{\"cmtid\":\"" + str (cmt_id) + "\"," , end = "") cmt_time_str = post_comm.find(ns[ "wp" ] + "comment_date_gmt" ).text cmt_time = time.mktime(time.strptime(cmt_time_str, '%Y-%m-%d %H:%M:%S' )) print ( "\"ctime\":\"" + str ( int (cmt_time * 1000 )) + "\"," , end = "") print ( "\"content\":\"" + clean_html(post_comm.find(ns[ "wp" ] + "comment_content" ).text) + "\"," , end = "") cmt_id = int (post_comm.find(ns[ "wp" ] + "comment_parent" ).text) + cmt_offset print ( "\"replyid\":\"" + str (cmt_id) + "\"," , end = "") cmt_author = post_comm.find(ns[ "wp" ] + "comment_author" ).text if cmt_author = = None : cmt_author = "本博客网友" try : cmt_userid = wp_users.index(cmt_author) + userid_offset except ValueError: cmt_userid = len (wp_users) + userid_offset wp_users.append(cmt_author) print ( "\"user\":{\"userid\":\"" + str (cmt_userid) + "\"," , end = "") print ( "\"nickname\":\"" + unicode_escape(cmt_author) + "\"," , end = "") cmt_author_url = post_comm.find(ns[ "wp" ] + "comment_author_url" ).text if None = = cmt_author_url: cmt_author_url = "" print ( "\"userurl\":\"" + cmt_author_url + "\"" , end = "") cmt_author_email = post_comm.find(ns[ "wp" ] + "comment_author_email" ).text if None ! = cmt_author_email: print ( ",\"usermetadata\":{\"email\":\"" + cmt_author_email + "\"}" , end = "") print ( "}," , end = "") print ( "\"ip\":\"" + post_comm.find(ns[ "wp" ] + "comment_author_IP" ).text + "\"," , end = "") print ( "\"channeltype\":\"1\"}," , end = "") print ( "]}" ) sys.stdout.flush() |
用法是先在wp后台的工具->导出->所有内容,如下:
拿到xml文件,然后改写脚本里的xml路径也好,直接拖到.py上运行也好,就能得到同名的畅言格式的.json文件,然后直接在畅言后台上导入畅言json格式评论即可(如果文件直接传文件过大的话就zip一下,反正我的乡下小博也就生成了几百k的json文件…)。
最后,由于畅言不像多说会默认回写wp本地评论,虽然有手动同步和实验室定时同步,但想想之前同步本地到畅言时报那个错…还是算了吧,我可不想我宝贵的wp本地评论里出现什么脏数据!但这样文章下面的评论数显示就又不正确了,看了下畅言文档,发现有js的获取畅言评论数说明,于是小改了一下,变成现在这样先显示本地评论数,再显示畅言评论数了。等什么时候畅言官方把这正反同步都完善了再改回去好了。
博主友情提示:
如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。
加载更多