[TOC]javascript
近几年,因为微信的流行,大部分人再也不频繁使用QQ,因此咱们对于本身的QQ数据并非特别了解。我相信,若是可以生成一份属于本身的QQ历史报告,那将是无比开心的一件事。html
目前网上关于QQ的数据分析工具较少,缘由是QQ相关接口比较复杂。而本程序的运行十分简单,具备良好的用户交互界面,只须要扫码登陆一步操做便可。java
目前本程序获取的数据包括:QQ详细数据、手机在线时间、非隐身状态下在线时间、QQ活跃时间、单向好友数量、QQ财产分析、群聊分析、过去一年我退出的群聊数据、退去一个月我删除的好友数据、全部代付信息、我最在乎的人以及最在乎个人人。因为相关的数据接口有访问限制,因此本程序并无对QQ好友进行分析。python
# 跳转到当前目录 cd 目录名 # 先卸载依赖库 pip uninstall -y -r requirement.txt # 再从新安装依赖库 pip install -r requirement.txt # 开始运行 python main.py
本程序分为多个模块,模块以下:git
首先,初始化相关文件夹,并调用qq_bot.py模块,定义一个qq bot对象,该对象为本程序的核心对象,全部数据获取均从该对象获取。
同时,本程序数据的报告文件为.md
格式github
# 初始化文件夹 init_folders() # 写入项目所需资源文件到本地目录 write_data() # 建立一个本身编写的qq bot对象 bot = Bot() custom_print(u'登陆成功,正在获取数据...') # 定义欲输出的markdown字符串 markdown_content = ''' <p align="center"> <font size='6px'>{qq_number}的我的QQ历史报告</font> <img src="{qq_icon_png}" align="right" height="60"> </p> ''' # 更新一下欲输出的markdown文本 markdown_content = markdown_content.replace('{qq_number}',bot.qq_number) markdown_content = markdown_content.replace('{qq_icon_png}', 'data/qq_icon.png')
登陆成功后,开始获取该登陆帐户的详细资料web
custom_print(u'正在获取该登陆帐户的详细数据...') detail_information = bot.get_detail_information() # content为markdown语法文本 content = '\n<br/><br/>\n' + '## 个人详细资料\n' + '种类|内容\n:- | :-\n' for key, value in detail_information.items(): if key == 'qq_level': star_count, moon_count, sun_count, crown_count = calculate_level(value) data = crown_count * '' + sun_count * '' + moon_count * '' + star_count * '' content += '{}|{}\n'.format(key_dict[key], data) else: content += '{}|{}\n'.format(key_dict[key], value) # 更新一下欲输出的markdown文本 markdown_content += content markdown_content += '\n> 注:单向好友表示他/她的列表中有你,而你的列表中没有他/她' # 每一个步骤完成后,保存markdown文件,以便防止程序出错时可以保存到最新的数据 with open('{}的我的QQ历史报告.md'.format(bot.qq_number), 'w', encoding='utf-8') as file: file.write(markdown_content)
接着,获取全部qq好友的备注名和qq号bash
all_qq_friends = bot.get_all_friends_in_qq() custom_print(u'全部qq好友号码和备注名中...') qq_number_list = [] for key, friend_group in all_qq_friends.items(): for info in friend_group['mems']: qq_number_list.append(info['uin'])
并获取全部群数据微信
# 获取全部群信息 custom_print(u'获取该QQ加入的全部群信息...') group_list = bot.get_group() print(group_list) # content为markdown语法文本 content = '\n\n<br/><br/>\n' + '## 我加入的群资料\n' + '序号|群名|群号|群主QQ\n:- | :-| :-| :-\n' # 获取某个群的群成员信息 for index, group in enumerate(group_list): group_number = group['gc'] group_name = group['gn'] owner = group['owner'] content += '{}|{}|{}|{}\n'.format(str(index+1), str(group_name), str(group_number), str(owner)) # 更新一下欲输出的markdown文本 markdown_content += content # 每一个步骤完成后,保存markdown文件,以便防止程序出错时可以保存到最新的数据 with open('{}的我的QQ历史报告.md'.format(bot.qq_number), 'w', encoding='utf-8') as file: file.write(markdown_content)
接下来的步骤如你所需,也就是获取其余相关的数据,因此本小节就不一一详细解释了,您能够查看相关源代码查看。获取的数据包括:markdown
此模块实现了获取qq数据的接口,主要经过抓包得到数据、分析数据,对参数进行加密解密等。
首先,是模拟扫码登陆id.qq.com,qun.qq.com,qzone.qq.com。三者登陆方式大同小异,惟一有区别的就是提交数据中的参数加密方式不一样。
咱们以id.qq.com登陆为例:
def login_id_qq_com(self): # 登陆id.qq.com # 访问网页,为了获取参数pt_login_sig login_url = 'https://xui.ptlogin2.qq.com/cgi-bin/xlogin?pt_disable_pwd=1&appid=1006102&daid=1&style=23&hide_border=1&proxy_url=https://id.qq.com/login/proxy.html&s_url=https://id.qq.com/index.html' html = get_html(login_url, '') # 对返回的cookies进行转化为dict类型,方便处理 cookies_back_dict = dict_from_cookiejar(html.cookies) pt_login_sig = cookies_back_dict['pt_login_sig'] self.cookies_merge_dict_in_id_qq_com.update(cookies_back_dict) # 访问网页,为了获取参数ptqrtoken qrcode_url = 'https://ssl.ptlogin2.qq.com/ptqrshow?appid=1006102&e=2&l=M&s=4&d=72&v=4&t=0.10239549811477189&daid=1&pt_3rd_aid=0' html = get_html(qrcode_url, '') # 对返回的cookies进行转化为dict类型,方便处理 cookies_back_dict = dict_from_cookiejar(html.cookies) qrsig = cookies_back_dict['qrsig'] ptqrtoken = hash33_token(qrsig) self.cookies_merge_dict_in_id_qq_com.update(cookies_back_dict) # 将二维码显示到图片框 BytesIOObj = BytesIO() BytesIOObj.write(html.content) qr_code = PIL.Image.open(BytesIOObj) image = PIL.ImageTk.PhotoImage(qr_code) image_label['image'] = image # 实时检测二维码状态 while (True): # 目标网址 target_url = 'https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://id.qq.com/index.html&ptqrtoken=' + str(ptqrtoken) + '&ptredirect=1&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1556812236254&js_ver=19042519&js_type=1&login_sig=' + str(pt_login_sig) + '&pt_uistyle=40&aid=1006102&daid=1&' # 登陆,须要带上访问cookies html = get_html(target_url, self.cookies_merge_dict_in_id_qq_com) # 返回的响应码为200说明二维码没过时 if (html.status_code): if ('二维码未失效' in html.text): custom_print(u'(1/3)登陆id.qq.com中,当前二维码未失效,请你扫描二维码进行登陆') elif ('二维码认证' in html.text): custom_print(u'(1/3)登陆id.qq.com中,扫描成功,正在认证中') elif ('登陆成功' in html.text): self.is_login = True custom_print(u'(1/3)登陆id.qq.com中,登陆成功') break if ('二维码已经失效' in html.text): custom_print(u'(1/3)登陆id.qq.com中,当前二维码已失效,请重启本软件') exit() # 延时 time.sleep(2) # 登陆成功后,把返回的cookies合并进去 self.cookies_merge_dict_in_id_qq_com = dict_from_cookiejar(html.cookies) self.cookies_merge_dict_in_id_qq_com.update(cookies_back_dict) # print(u'当前cookies:{}'.format(cookies_merge_dict)) # 获取这次登陆的qq号码 qq_list = re.findall(r'&uin=(.+?)&service', html.text) self.qq_number = qq_list[0] # 登陆成功后,会返回一个地址,须要对该地址进行访问以便获取新的返回cookies startIndex = (html.text).find('http') endIndex = (html.text).find('pt_3rd_aid=0') url = (html.text)[startIndex:endIndex] + 'pt_3rd_aid=0' # 屏蔽https证书警告 urllib3.disable_warnings() # 这里须要注意的是,须要禁止重定向,才能正确得到返回的cookies html = get(url, cookies=self.cookies_merge_dict_in_id_qq_com, allow_redirects=False, verify=False) # 把返回的cookies合并进去 cookies_back_dict = dict_from_cookiejar(html.cookies) self.cookies_merge_dict_in_id_qq_com.update(cookies_back_dict)
首先是访问指定网址,获取参数pt_login_sig
,其次是访问另一个网址,获取参数qrsig
,经过加密函数,将参数qrsig
转化为ptqrtoken
,而后就是获取二维码图片的状态了。当咱们检测到登陆成功时,就证实用户已经完成扫码操做,此时将网址返回的cookie保存下来。
这里要说明的是,加密函数的获取,须要具有必定的抓包基础才能获取获得。本程序的几个加密函数以下:
# 对qrsig进行基本的加密,该加密函数由抓包得到,须要具有必定抓包知识才能找到该加密函数 # 根据javascript版的加密函数,将其改写成python版本 def hash33_token(t): e, n = 0, len(t) for i in range(0,n): e += (e << 5) + ord(t[i]) return 2147483647 & e # 对skey进行基本的加密,该加密函数由抓包得到,须要具有必定抓包知识才能找到该加密函数 # 根据javascript版的加密函数,将其改写成python版本 def hash33_bkn(skey): e = skey t = 5381 for n in range(0,len(e)): t += (t << 5) + ord(e[n]) return 2147483647 & t
因为该模块下具备许多获取相关数据的qq接口,可是它们的形式很是类似,因此本节仅仅以获取全部qq群数据为例:
def get_group(self): # 获取全部群基本信息 # bkn由参数skey经过另外一个加密函数获得 bkn = hash33_bkn(self.cookies_merge_dict_in_qun_qq_com['skey']) submit_data = {'bkn': bkn} html = post_html('https://qun.qq.com/cgi-bin/qun_mgr/get_group_list', self.cookies_merge_dict_in_qun_qq_com, submit_data) group_info = loads(html.text) print(group_info) return group_info['join']
这里主要涉及到的仍是参数的加密、解密过程,这是一个难点,其余的话仍是比较简单的。
这个模块是绘制基本的gui模块,采用python内置的tkinter模块完成,用法至关简单,这里就不详细讲了。
这个模块主要是用来存储相关的数据的,在程序每次运行时,将该静态资源文件输出。这么作的缘由是能够防止用户将某些静态数据给删除了,致使程序运行错误。
完整版源代码存放在github上,有须要的能够下载
项目持续更新,欢迎您star本项目