新浪微博爬取笔记(4):数据清理
数据清理的部分很多,其实爬数据的过程中步骤的间隔也要做数据清理,都是很琐碎繁杂的工作。总结经验的话,就是:
1、一定要用数据库存储数据
(我因为还不太会数据库,为了“节省学习时间”,所有数据项都用txt存储,直到最后出现了多个种类之间查找,文件夹树变得比较复杂,才觉得当初即使使用MySQL也会提高效率)
2、处理异常的语句不嫌多
3、处理数据的脚本最好打包成函数,尽量减少运行前需要改源码的机会,变量从外部传递
4、工作流程要整体写出来画成图方便查找,步骤和文件多了会有点混乱
以处理时间为例:
我这次需要得到用户的latency, 也就是从微博发出到该用户转发的时间间隔。
一条微博的信息line在txt中是这样的:
M_CdHsYyHZd 转发[313] 04月17日 16:27 来自微博 weibo.com
一条转发:
/yunxiang 2014-09-28 12:46:07 来自火星Android /n/%E5%8D%9A%E7%89%A9%E6%9D%82%E5%BF%97
用python处理这样一条line, 基本需要的函数就是 .split() 以及各种列表操作;
以处理时间部分为例。python中用来处理时间的模块主要是datetime和time, datetime比较好用, time用来得到文件信息,比如创建、修改时间之类。
时间部分有不同的格式,比如:
今天 15:00
2014-12-04 20:49:48
31分钟前
04月17日 22:00
这样就要写不同的匹配方案:
1 if len(re.compile('\d+-\d+-\d+').findall(time_area[0])) == 1: #2014-12-04 20:49:48 2 [year, month, day] = [i for i in re.compile('\d+').findall(time_area[0])] 3 [hour, minute, sec] = [i for i in re.compile('\d+').findall(time_area[1])[0:3]] 4 t = [year, month, day] + [hour, minute, sec] 5 t = [int(i) for i in t] 6 resultTime = datetime.datetime(*t) 7 elif len([int(i) for i in re.compile('\d+').findall(time_area[0])]) == 1: # 31 minutes ago 8 postTime = file_time - datetime.timedelta(minutes = int(re.compile('\d+').findall(time_area[0])[0])) 9 resultTime = postTime 10 elif len([int(i) for i in re.compile('\d+').findall(time_area[0])]) == 2: #04 17 22:00 11 [year, month, day] = [file_time.year, re.compile('\d+').findall(time_area[0])[0], re.compile('\d+').findall(time_area[0])[1]] 12 [hour, minute, sec] = [re.compile('\d+').findall(time_area[1])[0], re.compile('\d+').findall(time_area[1])[1], 30] 13 t = [year, month, day] + [hour, minute, sec] 14 t = [int(i) for i in t] 15 resultTime = datetime.datetime(*t) 16 elif len(re.compile('\d+').findall(time_area[0])) == 0:#today 15:00 17 [year, month, day] = [file_time.year, file_time.month, file_time.day] 18 [hour, minute, sec] = [re.compile('\d+').findall(time_area[1])[0], re.compile('\d+').findall(time_area[1])[1], 30] 19 t = [year, month, day] + [hour, minute, sec] 20 t = [int(i) for i in t] 21 resultTime = datetime.datetime(*t) 22 else: 23 print "unexpected time type, check plz" 24 sys.exit(0)
需要注意很多细节部分,比如 len() 可以对列表求长度,也可以求字符串长度; re.compile() 匹配结果返回的是字符串;等等。
每一次运行完后生成的数据结构可以用pickle存储,在我的例子中所存储的是字典dict。用法是这样的:
1 import pickle 2 3 try: 4 with open('foreDic.pickle', 'rb') as f: 5 result = pickle.load(f) 6 except: 7 result = {}
这是在最开始时导入上次存储的数据结构。 pickle.load() 如果遇到了空文件会报错,因此处理这个异常,如果文件为空或是找不到文件,就新建一个空字典。
1 with open('foreDic.pickle', 'wb') as f: 2 pickle.dump(result, f)
最后将result字典存储到pickle文件中。