主要思路:

  1. 通过selenium+phantomjs模拟登录qq空间取到cookiesg_qzonetoken,并算出gtk
  2. 通过Requests库利用前面得到的url参数,构造http请求
  3. 分析请求得到的响应,是一个json,利用正则表达式提取字段
  4. 设计数据表,并将提取到的字段插入到数据库中
  5. 通过qq邮箱中的导出联系人功能,把好友的qq号导出到一个csv文件,遍历所有的qq号爬取所有的说说
  6. 通过sql查询和ipython分析数据,并将数据可视化
  7. 通过python的第三方库jiebawordcloud基于说说的内容做一个词云
  8. 通过selenium+phantomjs模拟登录qq空间取到cookiesg_qzonetoken,并算出gtk

    具体实现

    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
    import re
    from selenium import webdriver
    from time import sleep
    from PIL import Image
    #定义登录函数
    def QR_login():
    def getGTK(cookie):
    """ 根据cookie得到GTK """
    hashes = 5381
    for letter in cookie['p_skey']:
    hashes += (hashes << 5) + ord(letter)
    return hashes & 0x7fffffff
    browser=webdriver.PhantomJS(executable_path="D:\phantomjs.exe")#这里要输入你的phantomjs所在的路径
    url="https://qzone.qq.com/"#QQ登录网址
    browser.get(url)
    browser.maximize_window()#全屏
    sleep(3)#等三秒
    browser.get_screenshot_as_file('QR.png')#截屏并保存图片
    im = Image.open('QR.png')#打开图片
    im.show()#用手机扫二维码登录qq空间
    sleep(20)#等二十秒,可根据自己的网速和性能修改
    print(browser.title)#打印网页标题
    cookie = {}#初始化cookie字典
    for elem in browser.get_cookies():#取cookies
    cookie[elem['name']] = elem['value']
    print('Get the cookie of QQlogin successfully!(共%d个键值对)' % (len(cookie)))
    html = browser.page_source#保存网页源码
    g_qzonetoken=re.search(r'window\.g_qzonetoken = \(function\(\)\{ try\{return (.*?);\} catch\(e\)',html)#从网页源码中提取g_qzonetoken
    gtk=getGTK(cookie)#通过getGTK函数计算gtk
    browser.quit()
    return (cookie,gtk,g_qzonetoken.group(1))
    if __name__=="__main__":
    QR_login()

通过火狐浏览器的一个叫json-dataview的插件可以看到这个响应是一个json格式的

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
def parse_mood(i):
'''从返回的json中,提取我们想要的字段'''
text = re.sub('"commentlist":.*?"conlist":', '', i)
if text:
myMood = {}
myMood["isTransfered"] = False
tid = re.findall('"t1_termtype":.*?"tid":"(.*?)"', text)[0] # 获取说说ID
tid = qq + '_' + tid
myMood['id'] = tid
myMood['pos_y'] = 0
myMood['pos_x'] = 0
mood_cont = re.findall('\],"content":"(.*?)"', text)
if re.findall('},"name":"(.*?)",', text):
name = re.findall('},"name":"(.*?)",', text)[0]
myMood['name'] = name
if len(mood_cont) == 2: # 如果长度为2则判断为属于转载
myMood["Mood_cont"] = "评语:" + mood_cont[0] + "--------->转载内容:" + mood_cont[1] # 说说内容
myMood["isTransfered"] = True
elif len(mood_cont) == 1:
myMood["Mood_cont"] = mood_cont[0]
else:
myMood["Mood_cont"] = ""
if re.findall('"created_time":(\d+)', text):
created_time = re.findall('"created_time":(\d+)', text)[0]
temp_pubTime = datetime.datetime.fromtimestamp(int(created_time))
temp_pubTime = temp_pubTime.strftime("%Y-%m-%d %H:%M:%S")
dt = temp_pubTime.split(' ')
time = dt[1]
myMood['time'] = time
date = dt[0]
myMood['date'] = date
if re.findall('"source_name":"(.*?)"', text):
source_name = re.findall('"source_name":"(.*?)"', text)[0] # 获取发表的工具(如某手机)
myMood['tool'] = source_name
if re.findall('"pos_x":"(.*?)"', text):#获取经纬度坐标
pos_x = re.findall('"pos_x":"(.*?)"', text)[0]
pos_y = re.findall('"pos_y":"(.*?)"', text)[0]
if pos_x:
myMood['pos_x'] = pos_x
if pos_y:
myMood['pos_y'] = pos_y
idname = re.findall('"idname":"(.*?)"', text)[0]
myMood['idneme'] = idname
cmtnum = re.findall('"cmtnum":(.*?),', text)[0]
myMood['cmtnum'] = cmtnum
return myMood#返回一个字典

我们想要的东西已经提取出来了,接下来需要设计数据表,通过navicat可以很方便的建表,然后通过python连接mysql数据库,写入数据。这是创建数据表的sql代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE `mood` (
`name` varchar(80) DEFAULT NULL,
`date` date DEFAULT NULL,
`content` text,
`comments_num` int(11) DEFAULT NULL,
`time` time DEFAULT NULL,
`tool` varchar(255) DEFAULT NULL,
`id` varchar(255) NOT NULL,
`sitename` varchar(255) DEFAULT NULL,
`pox_x` varchar(30) DEFAULT NULL,
`pox_y` varchar(30) DEFAULT NULL,
`isTransfered` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

其实到这里爬虫的主要的代码就算完了,之后主要是通过QQ邮箱的联系人导出功能,构建url列表,最后等着它运行完成就可以了。这里我单线程爬200多个好友用了大约三个小时,拿到了十万条说说。下面是爬虫的主体代码。

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
#从csv文件中取qq号,并保存在一个列表中
csv_reader = csv.reader(open('qq.csv'))
friend=[]
for row in csv_reader:
friend.append(row[3])
friend.pop(0)
friends=[]
for f in friend:
f=f[:-7]
friends.append(f)
headers={
'Host': 'h5.qzone.qq.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0',
'Accept': '*/*',
'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'https://user.qzone.qq.com/790178228?_t_=0.22746974226377736',
'Connection':'keep-alive'
}#伪造浏览器头
conn = MySQLdb.connect('localhost', 'root', '123456', 'qq_mood', charset="utf8", use_unicode=True)#连接mysql数据库
cursor = conn.cursor()#定义游标
cookie,gtk,qzonetoken=QRlogin#通过登录函数取得cookies,gtk,qzonetoken
s=requests.session()#用requests初始化会话
for qq in friends:#遍历qq号列表
for p in range(0,1000):
pos=p*20
params={
'uin':qq,
'ftype':'0',
'sort':'0',
'pos':pos,
'num':'20',
'replynum':'100',
'g_tk':gtk,
'callback':'_preloadCallback',
'code_version':'1',
'format':'jsonp',
'need_private_comment':'1',
'qzonetoken':qzonetoken
}
response=s.request('GET','https://h5.qzone.qq.com/proxy/domain/taotao.qq.com/cgi-bin/emotion_cgi_msglist_v6',params=params,headers=headers,cookies=cookie)
print(response.status_code)#通过打印状态码判断是否请求成功
text=response.text#读取响应内容
if not re.search('lbs', text):#通过lbs判断此qq的说说是否爬取完毕
print('%s说说下载完成'% qq)
break
textlist = re.split('\{"certified"', text)[1:]
for i in textlist:
myMood=parse_mood(i)
'''将提取的字段值插入mysql数据库,通过用异常处理防止个别的小bug中断爬虫,开始的时候可以先不用异常处理判断是否能正常插入数据库'''
try:
insert_sql = '''
insert into mood(id,content,time,sitename,pox_x,pox_y,tool,comments_num,date,isTransfered,name)
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
'''
cursor.execute(insert_sql, (myMood['id'],myMood["Mood_cont"],myMood['time'],myMood['idneme'],myMood['pos_x'],myMood['pos_y'],myMood['tool'],myMood['cmtnum'],myMood['date'],myMood["isTransfered"],myMood['name']))
conn.commit()
except:
pass
print('说说全部下载完成!')

数据分析

学生QQ用的多还是微信用的多?

  1. 先用sql进行聚合分析,然后通过ipython作图,将数据可视化。
    统计一年之中每天的说说数目,可以发现每年除夕这一天是大家发说说最多的一天,可以看出2015年9月达到了一个高峰,主要因为数据是2015级的,所以在2015年九月大学入学的,之后开始下降,好多人开始玩微信,逐渐放弃了QQ,所以北石化学生用微信还是多。
  2. 通过下面这个年变化图可以更直观的看出QQ使用的频率越来越少,可能因为大学里班级,社团,活动有很多的微信群,越来越少的北石化学生使用QQ。

    学生晚上几点睡觉?

    通过这个每小时段说说发表的数目柱形图,可以发现大家在晚上22点到23点左右是最多的,另外中午十二点到一点也有一个小高峰!由此可见大多数学生在宿舍十一点熄灯后,并不会按时睡觉。

    学生的经济情况怎么样?

    用Excel的内容筛选功能,做了一个手机类型的饼图,通过这个饼图可以看出使用最多的手机是苹果,小米,魅族,华为这四个手机品牌,说明大多数大学生还是比较倾向于性价比比较高的手机,从某一方面可以体现大多数同学还是中等生活水平。

    学生都在说些什么?

    通过将mood表中的content字段导出为txt文本文件,利用pythonjiebawordcloud这两个第三方库,可以生成基于说说内容的词云.看看大家在国庆期间都再说些什么,很明显关于,习近平主席,国庆节,人民英雄纪念碑等关键词明显增多,同样也有计算机,英语,考试等关于学习的字段。