上周末花了两天时间,终于把博客迁移了过来,所有文章与图片都完整地保留在新博客中。
其实很早就有把博客转成独门博客的想法,一直拖没实现。最近正好趁百度空间升级,来了情绪,索性一下子换了过来。对了百度空间,用了四年了,感情也非常深,但是它有几个明显的缺点,让我一直耿耿于怀。首先就是写文章的时候,特别是写技术性的文章,帖代码没有格式化代码的功能,导致帖出来的代码格式非常乱,很难看。而且编辑器功能也比较弱,没办法定制。还有由于众所周知的原因,我发布的很多文章时不时会被和谐掉。前两天整理博客文章的时候,发现一共掉了一百多篇文章,可恶啊。不过还好百度官方提供了一个导出所有文章的功能,所以才很容易把所有文章迁移过来。还有百度的图片上传功能,简直弱爆了,上传的时候极不稳定,速度也不快,而且还限制大小为500K,超过500K它强制性压缩你的图片,当然压缩后的图片简直不能看。所以我发图片的时候还会多一道工序,就是检查大小,如果发现超过了500K,就用convert命令压缩一下图片。在发新文章的时候,它还会对文章内容进行关键词检查,发现在敏感词,就不让发布。
对此我还专门写了一个python脚本,专门对内容进行敏感词检查,我之前的文章有讲过。但是有的敏感词,并不在我的收录范围之内, 这时候就采用比较笨的办法“二分法”来找敏感词,就是一段一段地删除,看删除到哪里的时候就能发表成功,那么说明关键词就在那一段里面,逐一缩小范围,直到找出敏感词。有时候就为这一点就折腾好长时间才能发表成功,真是蛋疼。最后导火索就是百度空间即将进行的升级,把一个博客性质的系统活生生地变成了社交化的工具,类似点点网的那种,非常不爽,找不到那种个人领地的感觉了。还有就是升级的过程中,又把我的图片什么的搞丢了。百度每次升级都会出级这种技术问题,上一次丢了我好多文章,刚发的就莫名其妙地不见了,升级完后才恢复回来。
换博客还有一个好处,就是有了自己的服务器,这样很多东西就有条件捣鼓了,自己的一些想法,就随时可以写出来放在服务器上面跑。虽然发费了一些经济上的代价,不过我觉得就长远来说,肯定是值的。有的事情,迟早是要迈出第一步,能早就早点。
上面讲了迁移博客的背景与原因,下面着重讲一讲迁移的过程。由于文章与图片比较多,文章有将近2000篇,图片2500张左右,所以不可能人工手动来做这个事情啦。为此我写了很多个脚本,用了很多命令行工具,如grep/ack,sed,vim等。由于百度官方已经提供完整的文章打包下载功能,所以文章就省事了,虽然我也写过下载文章的python脚本,但是下载不了那些设置成隐私的文章。基于现有的文章,我迁移方案思路如下:
1、整理百度打包的文章,将文章的文件、发表时间、文章名按一定格式组织好,以便进行后处理。
2、获取文章分类,对每篇文章,从网上拉取文章的标题与分类,并与第一步中的文章名进行匹配,将文章分类加到第一步生成的列表中去。
3、对第二步处理后的列表进行分类检查,因为文章标题匹配肯定会有一些文章匹配不上,还有隐私的文章肯定匹配不上,对这些单独进行手动添加分类
4、对文章内容里面的图片链接进行处理。将图片下载到本地,然后将链接替换成相对路径(后面会结合wordpress系统的路径再一次处理)。
5、经过以上步骤,所有的数据都准备好了,最后一步就是将这些数据按照wordpress数据库指定的格式存到wordpress数据库中去。
第一步:
主要对打包下载好的索引文件blog_index.html进行处理,去掉不必要的信息,整理成比较规律的列表。这一步主要利用vim来实现,用vim的正规匹配替换功能。例如:
:%s/<\li>/<\/li>\r/g #把li后进行换行 :%s/<li class=".\{-}href ="//g #.\{-}为vim的非贪婪匹配
按照类型的步骤后,最后的效果如下:
第二步:
主要写了一个python脚本来实现下载分类信息 getCategory.py:
# coding=utf-8 import urllib #import os import codecs import thread def GetURLS(url): list0 = [] s1 = '<div class=tit><a href="' content = '' try: content = urllib.urlopen(url).read().decode('gbk') except: print url i = content.find(s1) if(i <> -1): content = content[i+len(s1):len(content)] while True: i = content.find(s1) if(i == -1): break content = content[i+len(s1):len(content)] i = content.find('"') str0 = content[0:i] str0 = 'http://hi.baidu.com'+str0 list0.append(str0) content = content[i:len(content)] return list0 def GetContent(url): s1 = u'title="查看该分类中所有文章">类别:' s2 = '</a>' #print url content = urllib.urlopen(url).read().decode('gbk') #print content i = content.find('<title>')+7 content = content[i:len(content)] j = content.find('_') title = content[0:j] i = content.find(s1) content = content[i+len(s1):len(content)] j = content.find(s2) content = content[:j] return content, title def ToHTML(content, name): name = name.replace('*', '') name = name.replace('/', '') name = name.replace('\\', '') name = name.replace(':', '') name = name.replace('?', '') name = name.replace('"', '') name = name.replace('<', '') name = name.replace('>', '') name = name.replace('|', '') name = name.replace('#', 'Sharp') filea = codecs.open('category.txt', 'a', 'utf-8') filea.write(name + ' | ' +content + '\r\n') filea.close() def downOne(url, sum0): content, title = GetContent(url) #mylock.acquire() #获取同步锁 #title = str(sum0)+','+title #print title #mylock.release() #释放同步锁 ToHTML(content, title) print title HiName = 'hacklzt' baseurl = 'http://hi.baidu.com/'+HiName+'/blog/index/' i = 0#博客分页 sum0 = 0 #文章总数 #多线程同步锁 mylock = thread.allocate_lock() headurl = '' while True: list0 = GetURLS(baseurl+str(i)) #print list0 if(len(list0) == 0): break if(list0[0] == headurl): break headurl = list0[0] for j in list0: sum0 = sum0+1 thread.start_new_thread(downOne,(j, sum0)) #downOne(j, sum0) i = i+1
下载后的格式如下图 category.txt:
然后将上面的结果与上一步的列表进行匹配整合的python脚本 sortCategory.py:
#!/bin/bash #encoding=utf-8 categorys = {} content = '' nocat = 0 for line in open('category.txt'): tmp_arr = line.split('|') categorys[tmp_arr[0].strip()] = tmp_arr[1].strip() for line in open('blog_index.html'): tmp_arr = line.split('|') title = tmp_arr[2].strip() cat = title in categorys.keys() and categorys[title] or '' if not title in categorys.keys(): nocat = nocat + 1 content += line.strip() + ' | ' + cat + '\r\n' print content open('index_blog-cat.html', 'w').write(content) print 'NO:' + str(nocat) #打印不匹配的总数
第三步:
检查有哪些文章没有匹配上分类,打印出来,同样也是python脚本来完成 checkCategory.py:
#!/bin/bash #encoding=utf-8 for line in open('index_blog-cat.html'): tmp_arr = line.strip().split('|') if tmp_arr[-1].strip() == '': print line
合并后的格式如图:
图片的文章顺序是我颠倒了的,因为后插入到数据库中时,要先插入老的文章,颠倒文本内容顺序也很简单,一个命令搞定:
tac index_blog-cat.html > index_blog-cat-rsort.html
第四步:
这一步将文章内容(百度打包里面的html文件)中的图片链接进行替换,主要利用grep、ack与sed命令接合来实现,例如:
sed -i 's/src="pics\/hiphotos.baidu.com\/hacklzt\/pic\/item/src="../wp-content/uploads/hibaidu/g' blog/*.html #注意\的转义作用
考虑到不仅要替换链接,还要将图片下载到本地,于是写了一个shell脚本来完成 pics.sh:
#/bin/bash #encoding=utf8 grep -o -P ' pics.url #将图片地址保存 while read line; do fname=`echo ${line} |awk -F/ '{print $NF}'` #找出图片地址的文件名 echo ${line}' '${fname} regurl=${line//\//\\\/} #正则匹配时,将/替换成\/ sed -i "s/${regurl}/pics\/${fname}/g" blog/*.html #正则替换图片地址 #echo "curl -o pics/${fname} ${line} > /dev/null" #下载图片 curl -o pics/${fname} ${line} > /dev/null #下载图片 done < pics.url #从文件中读取每一行进行处理
第五步:
到现在为止,我们要做的数据准备工作已经完成了。最后写了一个php脚本,把文章内容与时间等信息,存到wordpress相应的数据表中。post2wp.php内容如下:
<!--?php date_default_timezone_set('Asia/Chongqing'); $index_file = 'index_blog-cat.html'; $f_handle = fopen($index_file, 'r'); while(!feof($f_handle)){ $line = fgets($f_handle); if(empty($line)) break; $line_arr = explode('|', $line); $blog_file = trim($line_arr[0]); $date_time = trim($line_arr[1]); $title = htmlspecialchars(trim($line_arr[2])); $cat = trim($line_arr[3]); processBlog($blog_file, $title, $date_time, $cat); } $sql = 'update wp_term_taxonomy w1 set w1.count = (select count(*) from wp_term_relationships where term_taxonomy_id = w1.term_taxonomy_id)'; $res = mysql_query($sql); //更新每个目录下面有多少文章 function processBlog($blog_file, $title, $date_time, $cat){ $cat_arr = array( '默认分类' => 1, '工具教程' => 3, '技术文章' => 4, '个人日记' => 5, '编程相关' => 6, 'delphi编程' => 7, '精品文章' => 8, '原创作品' => 9, '学习笔记' => 10, '网页编程' => 11, '.net编程' => 12 ); $handle = fopen($blog_file, 'r'); $blog_content = fread($handle, filesize($blog_file)); $blog_content = mysql_real_escape_string($blog_content); $post_time = strtotime($date_time); $post_time_gmt = date('Y-m-d h:i:s', $post_time - 8*3600); //echo $post_time_gmt; exit(); $sql = "INSERT INTO wp_posts ( post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt,post_status, comment_status, ping_status, post_password, post_name, to_ping, pinged, post_modified, post_modified_gmt, post_content_filtered, post_parent, guid, menu_order, post_type, post_mime_type, comment_count) VALUES (" ."1,'{$date_time}', '{$post_time_gmt}', '{$blog_content}', '{$title}'," . "'', 'publish', 'open', 'open', ''," . "'', '', '', '{$date_time}', '{$post_time_gmt}', " . "'', 0, '', 0, 'post', " . "'', 0);"; //echo $sql; exit(); mysql_connect('localhost', 'root', 'hacklzt'); mysql_select_db('wp_blog'); mysql_query('SET NAMES UTF8;'); $res = mysql_query($sql); //插入文章 if(empty($res)){ echo "$title 失败"; } $ins_id = mysql_insert_id(); if(array_key_exists($cat, $cat_arr)){ $sql = "INSERT INTO wp_term_relationships (object_id, term_taxonomy_id, term_order) ". "VALUES ($ins_id, $cat_arr[$cat], 0);"; $res = mysql_query($sql); //插入此文章的分类 if(empty($res)){ echo "$title 分类失败"; }else{ } }else{ echo "$title 分类失败"; } } ?>
用命令 php post2wp.php,就可以直接运行该php文件。
OK,收工。
此外,现发现文章里面的链接不对,可以用SQL语句来修正:
UPDATE wp_posts SET post_content = REPLACE( post_content, '原内容', ' 新内容' ) ;
其实上面的脚本我是调试了很久才最终完成的,所以程序不是写出来的,是调出来的,哈哈。