python爬虫qq好友信息_qq好友空间说说爬虫
这篇日志主要记录、总结自己写的一个小爬虫,算是自己学习python的小练习吧。
这个爬虫主要实现了爬取qq好友们2018年的说说、提取关键信息并且存入excel文件的功能。
该爬虫使用的python版本是python3。
其中,selenium库用于登陆访问页面,requests库用于向网页发送请求、re库用于匹配、提取返回包含说说信息的内容,openpyxl库用于储存信息,time库用于计算程序运行时间。
程序源码放在了GitHub上iszff/QQ-Crawler。
爬虫思路
使用selenium登陆空间
selenium是一个自动化测试工具,它可以寻找、定位、选择网页中的元素,向网页提交一些信息,如输入用户名、密码,也可以获取页面中的信息,如返回当前页面的url、网页源码。
进入好友空间说说页面、登陆并获取信息: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
39def (url, qq, password):
driver = webdriver.Chrome()
driver.set_page_load_timeout(10)
driver.get(url)
time.sleep(6)
driver.switch_to.frame('login_frame')
driver.find_element_by_xpath('//*[@id="switcher_plogin"]').click()#点击选择
driver.find_element_by_xpath('//*[@id="u"]').clear()
driver.find_element_by_xpath('//*[@id="u"]').send_keys(qq)#输入账号
driver.find_element_by_xpath('//*[@id="p"]').clear()
driver.find_element_by_xpath('//*[@id="p"]').send_keys(password)#输入密码
driver.find_element_by_xpath('//*[@id="login_button"]').click()
time.sleep(6)
html = driver.page_source#返回页面内容,根据内容判断内否进入空间
fw = re.findall(r'主人设置了权限,您可通过以下方式访问',html)#判断好友空间是否限制权限
if len(fw)!=0:
driver.delete_all_cookies()
driver.quit()
return 0,0,0
else:
cookies = driver.get_cookies()#获取cookie
cookie = {}
for elem in cookies:
cookie[elem['name']] = elem['value']
driver.delete_all_cookies()
hashes=5381
for letter in cookie['p_skey']:
hashes += (hashes << 5) + ord(letter)
gtk=str(hashes & 0x7fffffff)
g_qzonetoken = re.findall(r'window.g_qzonetoken = (function(){ try{return ".*?"',html)
qzonetoken=g_qzonetoken[0].split('"')[-2]
driver.quit()
return cookie, gtk, qzonetoken
通过观察浏览器控制台中的请求头,发现请求连接中有g_tk和qzonetoken这两项
而且两项都是动态变化的,每次刷新都会变化,不过经过多次…尝试,似乎qzonetoken的变化影响不大
qzonetoken包含在页面的源代码中,可以通过正则匹配直接获得
在js内容找出可以找出一个g_tk的加密算法(向大佬们低头)
使用requests向网页发送请求
requests可以通过传递参数向网络发送http请求,可以获得不同类型的Response内容。
官方文档写的很不错。
构造链接1
2
3
4
5
6
7
8
9urlOrd = 'https://user.qzone.qq.com/proxy/domain/taotao.qq.com/cgi—bin/emotion_cgi_msglist_v6?uin='
sec='&ftype=0&sort=0&pos='
third='&num=20&replynum=100&g_tk='
forth='&callback=_preloadCallback&code_version=1&format=jsonp&need_private_comment=1&qzonetoken='
fifth='&g_tk='
for ye in range(400):
pos = str(ye*20)
emotionurl=urlOrd+ friend_qq + sec + pos + third + gtk + forth + qzonetoken+ fifth + gtk
观察确定请求url格式,构造请求url
对网页请求1
2
3
4def get_emotion(url,cookie):
header= {'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.8', 'host': 'h5.qzone.qq.com', 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'connection': 'keep-alive'}
r = requests.get(url, headers=header, cookies=cookie)
return r.text #返回文本信息
获取好友信息
获取好友信息的爬虫思路和获取说说页面响应的思路基本一致,只是url有所改变。
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
41def enter_qzone(my_qq, my_password, save_path):#进入网页 获取cookies 构造链接
url = 'https://user.qzone.qq.com/'+my_qq+'/311'
(cookie, gtk, qzonetoken) = login_in(url, my_qq, my_password)
urlOrd = 'https://user.qzone.qq.com/proxy/domain/r.qzone.qq.com/cgi-bin/tfriend/friend_hat_get.cgi?hat_seed=1&uin='
second ='&fupdate=1&g_tk='
third = '&qzonetoken='
fourth = '&g_tk='
haturl= urlOrd + my_qq + second + gtk + third + qzonetoken + fourth + gtk
textpage = get_friendhat(haturl, cookie)
process_save(textpage,save_path)
def get_friendhat(url,cookie):#发送请求 获取响应
header= {'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.8', 'host': 'h5.qzone.qq.com', 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'connection': 'keep-alive'}
r = requests.get(url, headers=header, cookies=cookie)
return r.text
def process_save(text,save_path):#提取信息并储存
friend=re.findall('".*?":{n"realname":".*?"}',text)
frNum = len(friend)
Name = []
for elem in friend:
n =elem.split('"realname":"')[1].split('"}')[0]
Name.append(n)
QQ = []
for elem in friend:
q = elem.split('"')[1]
QQ.append(q)
wb = load_workbook(save_path)
ws = wb.get_sheet_by_name("friend_info")
wc_name=ws['A2':'A'+str(frNum+2)]
wc_qq=ws['B2':'B'+str(frNum+2)]
for i in range(frNum):
wc_name[i][0].value = Name[i]
wc_qq[i][0].value = QQ[i]
wb.save(save_path)
使用正则表达式re库提取信息
观察响应信息的内容,不难发现它的表达方式是json格式。
可以直接使用Requests库中内置的JSON解码器r.json()
当时写代码的时候…没想起来( ̄。。 ̄),直接暴力的用正则对文本内容进行了正则匹配,不过也达到了提取信息的目的
这里使用的方法是对返回的一个很长很长的字符串的文本信息进行正则匹配,这一块就没什么好说的了,只要对正则的使用比较熟练就很方便。
正则表达式的常用操作符操作符
说明
.
表示任何单个字符
[ ]
字符集,对单个字符给出取值范围
[^ ]
非字符集,对单个字符给出排除范围
*
前一个字符出现0次或无限次扩展
+
前一个字符出现1次或无限次扩展
?
前一个字符0次或1次扩展
|
左右表达式任取其一
{m}
扩展前一个字符m次
{m,n}
扩展签一个字符m至n次(含n)
^
匹配字符串开头
$
匹配字符串结尾
()
分组标记,内部只能使用|操作符
d
数字
w
单词字符
要注意正则表达式默认的是贪婪匹配,即趋于最大匹配长度,使用*?可以实现最小匹配
另一点需要注意的地方就是转义字符的问题
re库的函数函数
说明
re.search()
在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match()
从一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall()
搜索字符串,一列表类型返回全部能匹配的字符串
re.split()
将一个字符串按照正则表达式匹配结果进行分割,返回列表
re.finditer()
搜索字符串,返回匹配结果的迭代类型,每个迭代元素是match对象
re.sub()
在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
re库本生就有很多好用的函数,当时写代码的时候也没怎么想起来( ̄。。 ̄)
当时在返回信息中并没有找到发说说时刻这个信息,created_time对用的是一串数字,通过我咳咳…细心的观察发现这一串数字是秒数,发说说的具体时间是按照秒数计算的。通过对几条说说的观察算出1514649600是2018年1月1日00:00对应的秒数。当时还有专门去算一下对应的0代表的是哪个时间点,算出来是1970年1月1日08:00,一开始还以为是马化腾生日(+_+)。后来也算是偶然知道了unix时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,很多语言后来也是这样如java、python。
1
2
3h = postTime.split(',"created_time":')[1].split(',"editMask"')[0]
hour = ( int(h) - 1514649600 ) %86400 /3600#算出一天中发说说的时刻
ssInfo.append(hour)
使用openpyxl将信息存入excel文件中、
openpyxl提供了很多方便操作.xlsx文件的函数,通过Sheet、cell的操作可以访问、读写单元格。
本来是想用数据库的,但是并不会数据库,配置文件弄了半天也没弄好,就选择操作excel文件。
存储信息量太大的话最好不要存在一个文件中,加载会变慢
最终爬取了200多位好友2018年的说说,共5000多条。
储存在excel中的结果。
数据可视化
对好友空间是否对自己开放情况进行了统计,绘制饼状图accessablePie。
按照月份对好友们发说说条数绘制柱状图monthHist。
按照小时对好友们发说说条数绘制柱状图hourHist。
本文参照了标标的专栏文章爬取QQ空间。
题外话
其实代码写得挺烂的,异常处理做的也不好,跑起来遇到了异常才对应的写异常处理。
另外就是网速要好o(≧口≦)o,不然requests就会报错,校网实在不能打,所以我选择去网吧(≧∇≦)。
算是一个上学期的一个小总结,也算是这学期的开始吧。
因为代码是上学期最后写的,这篇总结一直拖到了这学期开学才写,再不写就要上课了Orz。
希望大三一切都顺利吧,至少能够顺心意。
st=>start: 开始
op1=>operation: 登陆好友空间说说页面、获取cookie
op2=>operation: 构造请求、获取返回内容
op3=>operation: 处理返回内容、提取信息
e=>end
st->op1->op2->op3->e{"0":{"scale":"1,"},"1":{"line-width":"2,"},"2":{"line-length":"50,"},"3":{"text-margin":"10,"},"4":{"font-size":12},"scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12}
python爬虫qq好友信息_qq好友空间说说爬虫相关推荐
- Python实现QQ PC端给好友发送消息
上一篇说了发现有交易机会时可以发邮件,如果不想下载邮箱app的话,也可以通过qq来提醒自己. 具体的方法就是先查找qq的句柄,然后用SendMessage给qq窗口发送消息.这样的前提就是跟好友的聊天 ...
- Java登陆3GQQ以及获取好友信息与好友聊天的简单实现
2019独角兽企业重金招聘Python工程师标准>>> 主要是通过java实现3GQQ的登陆,抓取好友信息(昵称,QQ号等等),以及获取聊天信息等等. 代码的灵感来自 @水之子哈哈 ...
- Python 爬取网页信息并保存到本地爬虫爬取网页第一步【简单易懂,注释超级全,代码可以直接运行】
Python 爬取网页信息并保存到本地[简单易懂,代码可以直接运行] 功能:给出一个关键词,根据关键词爬取程序,这是爬虫爬取网页的第一步 步骤: 1.确定url 2.确定请求头 3.发送请求 4.写入 ...
- java仿qq好友列表_QQ好友列表树形列表java代码实现代码
以前在网上瞎转悠的时候就发现很多人为用Java实现QQ登陆后的面板的问题感到十分头疼,最近我因在写模拟QQ的项目,故不可或缺的遇到了这一个问题,在网上我google了,百度了,最终发现的是有很多人被这 ...
- python怎么打开qq_如何用python登陆qq读取信息
def CheckVerify(self,uin): check="h" check=check.replace('{uin}',uin) pattern=re.compile(& ...
- 京东搜索页爬虫商品店铺信息
京东搜索页爬虫商品店铺信息 1.写好整个爬虫框架 2.用requests库获取网页源代码 3.正则表达式获取需要的相关信息 4.把获取的信息写入excel中并保存到电脑 完整代码 工作需要需获取京东商 ...
- 分布式网络爬虫关键技术分析与实现一网络爬虫相关知识介绍
搜索引擎发展的历史过程与发展现状 1搜索引擎的发展的历史 1990年以前,没有任何人能搜索互联网.所有搜索引擎的祖先,是1990年由Montreal的McGill University学生Alan E ...
- python爬虫qq好友信息,GitHub - equationl/QQzone_crawler: QQ 空间动态爬虫,利用cookie登录获取所有可访问好友空间的动态保存到本地...
关于 Edit by equationl 优先在 码云 上更新 该项目修改自 xjr7670 的 QQzone_crawler 原作者说明: QQ空间动态爬虫 修改了什么? 爬取完整的评论列表 爬取点 ...
- 爬虫实战-python爬取QQ群好友信息
自从开始学习爬虫后,总是无法控制那一颗躁动的心.每天总是想要爬点什么,爬过电影.爬过电影影评.爬过图片(美女图).爬过视频链接,从最初的简单解析网页到模拟登陆再到异步加载,现在看到一个网页最先想的就是 ...
- python爬虫-从QQ邮箱获取好友信息并爬取头像
本篇博客利用python爬虫实现半自动爬取好友头像 和以前一样,先上效果: 以上就是我的好友头像,怎么获取呢? 我采取的方法可能有点低级,首先打开我们的qq邮箱,按F12找见如下的包: 我们需要的好友 ...
最新文章
- 鸡啄米vc++2010系列32(标签控件Tab Control 下)
- 王维嘉:神经网络的本质是在数据里面提取相关性
- easyui messager 消息框 对话框
- Java多线程--synchronized修饰普通方法和修饰静态方法的区别
- Android实现笔记本修改功能,安卓12第二个开发者预览版推出:UI、功能有所改进...
- 工业级光模块是什么?
- 关于ssm框架的整合(二) 2021.05.10
- Java判断奇数偶数-高效率
- 辽宁工业大学计算机复试经验,辽宁工业大学车辆工程考研经验
- 阿里面试官:HashMap 熟悉吧?好的,那就来聊聊 Redis 字典吧!
- Win7如何硬盘安装Ubuntu实现双系统
- 怎么用软件测试相似相似度,文档相似性检测工具
- 蓝的成长记——追逐DBA(11):回家后的安逸,晕晕乎乎醒了过来
- 关于微信投票活动存在微信人工刷票数的情况解析
- buu(前三页第二弹) RSA习题与相关知识总结
- 2月14,情人节双语送祝福!
- Git add回退 commit回退
- [免费专栏] Android安全之数据存储与数据安全「详解」
- 阿里Java编码手册实战详解-集合处理篇
- 【机器学习】LDA算法原理
热门文章
- 老式计算机如何设置u盘启动,技嘉主板老式bios设置u盘启动教程
- 名老中医经验继承研究现状及“中医处方智能分析系统”应用前景
- steam错误代码100怎么办
- dagger2简单使用与理解笔记
- 文本界面听歌神器--moc
- oracle12c分片应用场景,Oracle 12cR2数据库(Oracle12.2)新特性之四:Sharding 的增强...
- python编写dll文件_.dll 文件编写和使用
- 动态规划之矩阵连乘问题详细解读(思路解读+填表+代码)
- C语言自学之路八(数组(重点)详解)
- 【MATLAB】MATLAB数值计算