使用Python爬取QQ好友的说说
程序员文章站
2022-04-26 08:09:54
...
个人博客
前几天把QQ好友的说说爬了下来 统计一下大概爬了有12W条数据 然后把这些数据进行了简单的可视化 分析完之后 突然想到可不可以把每个好友的进行分析 分析思路一样 只要前端输入相应的QQ 就能显示该QQ的分析结果 或者听同学的建议做一个随缘APP摇一摇手机就可看到其他人的说说 想想挺好玩儿 等有时间了把这个做了 完美
开发环境:
- python3.5
- MySQL5.7
- Ubuntu16.04LTS
- Python第三方库
- selenium
- Requests
- pymysql
- jieba
- wordcloud
QQ空间爬虫步骤:
- 通过selenium+phantomjs模拟登录qq空间取到cookies和g_qzonetoken,并算出gtk(因为请求参数加密了)
- 通过Requests库通过前面获取的URL参数 构造http请求
- 分析请求响应 利用正则匹配出想要的字段(也可以用json库直接取)
- 根据匹配的信息设计数据库表 入库
- 通过qq邮箱的导出联系人功能 把好友QQ号导出csv文件 然后遍历所有的QQ号爬取所有的说说
- 后续的数据分析
代码实现
- 通过selenium+phantomjs模拟登录qq空间取到cookies和g_qzonetoken,并算出gtk(因为请求参数加密了)
from selenium import webdriver
import time
import re
#获取cookie,g_tk,g_qzontoken这三个数据
def Login_QQ():
'''gtk解密'''
def getGTK(cookie):
""" 根据cookie得到GTK """
hashes = 5381
for letter in cookie['p_skey']:
hashes += (hashes << 5) + ord(letter)
gtk=hashes&0x7fffffff
return gtk
browser=webdriver.Chrome()
url = "https://qzone.qq.com/" # QQ登录网址
browser.get(url)
browser.switch_to.frame('login_frame')#定位账号密码登录
browser.find_element_by_id('switcher_plogin').click()
browser.find_element_by_id('u').clear()
browser.find_element_by_id('u').send_keys('') # 这里填写你的QQ号
browser.find_element_by_id('p').clear()
browser.find_element_by_id('p').send_keys('') # 这里填写你的QQ密码
browser.find_element_by_id('login_button').click()
time.sleep(1)
print(browser.title) # 打印网页标题
# print(browser.get_cookies())
cookie={}
for element in browser.get_cookies():
cookie[element['name']]=element['value']
print('Get the cookie of QQlogin successfully!(共%d个键值对)' % (len(cookie)))
print(cookie)
html = browser.page_source # 保存网页源码
pattern = re.compile(r'window\.g_qzonetoken = \(function\(\)\{ try\{return "(.*?)";\}')
g_qzonetoken=re.search(pattern,html)
print(g_qzonetoken.group(1))
gtk=getGTK(cookie)#通过getGTK函数计算gtk
return (cookie,gtk,g_qzonetoken)
其实也可以用selenium的截屏功能进行扫码登录
通过Requests库利用前面得到的url参数,构造http请求
打开自己空间 然后开起浏览器开发者模式 点击XHR 和 Preservce log
然后在自己空间上点击说说 会发现这么一个URL(emotion_cgi_msglis_v6?uin=×××××)
点击preview 会发现里面就是我们需要的信息
在该请求头中 会发现有两个参数是我们不确定的
g_tk
qzonetoken
其中g_tk是通过某个加密算法所生成的g_tk 具体讲解
而qzonetoken 可直接在网页源码中找到
获取构造的请求参数之后 即可构造url然后用正则提取需要的字段(因为觉得正则比较炫酷 所以就采用了正则)
def parse_mood(i):
'''从返回的json中,提取我们想要的字段'''
qq=get_qq()
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
获取数据之后入库
创建表
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列表 就可以爬取所有好友的信息了(没有访客记录)我用单线程爬了大概3个小时
爬虫代码
mport pymysql
import re
import requests
import datetime
from qq.Login import Login_QQ
from qq.getFriends import getFriends
from qq.mood import parse_mood
host='localhost'
user=''
pwd=''
db=''
con=pymysql.connect(host,user,pwd,db,use_unicode=True, charset="utf8")#可中文入库
cursor=con.cursor()
con.autocommit(True)
# 伪造浏览器头
headers = {
xxx
}
cookie,gtk,qzonetoken=Login_QQ()#通过登录函数取得cookies,gtk,qzonetoken
s=requests.session()#用requests初始化会话
friends=getFriends()
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,
'g_tk': gtk
}
response=s.request('GET','https://user.qzone.qq.com/proxy/domain/taotao.qq.com/cgi-bin/emotion_cgi_msglist_v6?',params=params,headers=headers,cookies=cookie)
if response.status_code==200:
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:
# #去重
# same_sql = '''
# select %s from mood
# '''
# cursor.execute(same_sql,myMood['id'])
# if cursor.fetchall():
# print("已经爬过该说说")
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']))
except:
pass
print('说说全部下载完成!')
爬虫的内容结束 后面的数据分析 我是用Flask+Echarts完成的 步骤后续添加
上一篇: python爬虫(1)
下一篇: 移动应用开发跨平台工具imag.js入门