一键生成属于自己的QQ历史报告,看看你对自己的QQ了解程度有多深?

简介

近几年,由于微信的流行,大部分人不再频繁使用QQ,所以我们对于自己的QQ数据并不是特别了解。我相信,如果能够生成一份属于自己的QQ历史报告,那将是无比开心的一件事。

目前网上关于QQ的数据分析工具较少,原因是QQ相关接口比较复杂。而本程序的运行十分简单,具有良好的用户交互界面,只需要扫码登录一步操作即可。

目前本程序获取的数据包括:QQ详细数据、手机在线时间、非隐身状态下在线时间、QQ活跃时间、单向好友数量、QQ财产分析、群聊分析、过去一年我退出的群聊数据、退去一个月我删除的好友数据、所有代付信息、我最在意的人以及最在意我的人。由于相关的数据接口有访问限制,所以本程序并没有对QQ好友进行分析。

功能截图







如何运行

# 跳转到当前目录
cd 目录名
# 先卸载依赖库
pip uninstall -y -r requirement.txt
# 再重新安装依赖库
pip install -r requirement.txt
# 开始运行
python main.py

编写思路

本程序分为多个模块,模块如下:

  1. main.py,主程序,用于获取并处理相关数据,并导出数据报告。
  2. qq_bot.py, 核心模块,实现了qq相关的接口,较为复杂。
  3. tkinter_gui.py,绘制gui模块,使用tkinter绘制基本的交互界面。
  4. static_data.py,数据存储模块,所有数据采用base64编码存储。

main.py模块

首先,初始化相关文件夹,并调用qq_bot.py模块,定义一个qq bot对象,该对象为本程序的核心对象,所有数据获取均从该对象获取。

同时,本程序数据的报告文件为.md格式

	# 初始化文件夹
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')

登录成功后,开始获取该登录账户的详细资料

    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 * '![](data/level_crown.png)' + sun_count * '![](data/level_sun.png)' + moon_count * '![](data/level_moon.png)' + star_count * '![](data/level_star.png)'
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号

    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)

接下来的步骤如你所需,也就是获取其他相关的数据,所以本小节就不一一详细解释了,您可以查看相关源代码查看。获取的数据包括:

  1. 获取过去30天内退出的群名单
  2. 获取过去364天内删除的好友名单
  3. 判断此次登录的qq是否为vip或者svip
  4. 获取qb值
  5. 获取代付信息
  6. 亲密度排行榜
  7. 共同好友数
  8. 成为好友的天数

qq_bot模块

此模块实现了获取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']

这里主要涉及到的还是参数的加密、解密过程,这是一个难点,其他的话还是比较简单的。

tkinter_gui模块

这个模块是绘制基本的gui模块,采用python内置的tkinter模块完成,用法相当简单,这里就不详细讲了。

static_data模块

这个模块主要是用来存储相关的数据的,在程序每次运行时,将该静态资源文件输出。这么做的原因是可以防止用户将某些静态数据给删除了,导致程序运行错误。

补充

完整版源代码存放在github上,有需要的可以下载

项目持续更新,欢迎您star本项目

License

The MIT License (MIT)

一键生成属于自己的QQ历史报告,看看你对自己的QQ了解程度有多深?的更多相关文章

  1. 一键生成HTML4和WAP站

    前两天在QQ空间上提到微信上线风铃时,把其中的HTML5错打成HTML4,结果发现很多媒体微博照着转载,依旧说成 "一键生成HTML4和WAP站",这就是转载不注明出处.不署名.不 ...

  2. 个人永久性免费-Excel催化剂功能第57波-一键生成完全组合的笛卡尔积结果表

    在数据库的多表查询中,通常会有各种连接关系,同样地在Excel环境中,也有很大的场景需要用到类似数据库的多表查询,如经典的VLOOKUP就是其中一种类似LEFT JOIN查询的查询效果.在很多时候需要 ...

  3. [Java 开源项目]一款无需写任何代码,即可一键生成前后端代码的工具

    作者:HelloGitHub-小鱼干 JeecgBoot 是一款基于代码生成器的低代码开发平台,零代码开发.JeecgBoot 采用开发模式:Online Coding 模式-> 代码生成器模式 ...

  4. 开源框架 WebFirst 一键生成项目,在线建表

    1.WebFirst框架描述 WebFirst  是果糖大数据团队开发的新一代 高性能 代码生成器&数据库设计工具,由.net core 3.1 + sqlsugar 开发 导入1000个表只 ...

  5. 一键生成APP官网

    只需要输入苹果下载地址,安卓市场下载地址,或者内测下载地址,就能一键生成APP的官网,方便在网上推广. 好推APP官网 www.hotapp.cn/app

  6. Ant搭建 一键生成APP技术 平台

    1.博客概要 本文详细介绍了当今流行的一键生成APP技术.介绍了这种设计思想的来源,介绍了国内外的研究背景,并介绍了这个技术体系中的一些实现细节,欢迎各路大神们多提意见.一键生成技术,说的通俗点就是, ...

  7. 使用sencha cmd 一键生成你的应用程序代码

    一键生成你的应用程序代码: ------------------------------------------------------------ 我们的出发点就是使用命令来产生一个应用程序,执行以 ...

  8. Automator一键生成所需的iOS 图片icon

    iOS到8了, 终于受不了它的各种尺寸的icon了. 写一个Finder服务来一键生成吧. 拖放几次再重复, 无技术含量, 但很有用. // 存放目录    ~/资源库/Services/

  9. PHP通过(PDO)Mysql表字段一键生成创建sqlite的SQL

    首发于:http://www.zzzzy.com/201406053158.html /** * Mysql表字段一键生成创建sqlite的SQL 2 * @author: Skiychan < ...

随机推荐

  1. hdu6062RXD and logic gates多校题 构造

    听说标算的点数是2^(n+1)级别的,也不知道我是不是比标算优一点? (话说这种题一眼看过去怎么跟题答一样) 然而并不是题答,没法手玩,来考虑一下一般解法: 考虑一个规模较小的问题:最后一位一定是0 ...

  2. 算法设计与分析-HomeWork

    ex1(p20) 代码如下: import random def Darts(n): k=0 i=1 while i<=n: x=random.uniform(0,1) #y=random.un ...

  3. 什么是.NET for Apache Spark?

    什么是.NET for Apache Spark? 分享一个.NET平台开源免费跨平台的大数据分析框架.NET for Apache Spark for Apache Spark   今天早上六点半左 ...

  4. net core 中间件管道

    net core 中间件管道 .net core 管道(Pipeline)是什么? 由上图可以看出,.net core 管道是请求抵达服务器到响应结果返回的中间的一系列的处理过程,如果我们简化一下成下 ...

  5. Ubuntu 下修改Tomcat和Jetty默认的JDK和初始内存

    修改/etc/default/tomcat  或者  /etc/default/jetty   文件 中的 JAVA_HOME 和 JAVA_OPTS

  6. 获取jqGrid中选择的行的数据

    下面可以获取选择一行的id,如果你选择多行,那下面的id是最后选择的行的id: var id=$(‘#gridTable’).jqGrid(‘getGridParam’,'selrow’); 如果想要 ...

  7. WinForm 开发框架 Jade UI Beta

    Jade UI Demo Beta 个人网站:http://www.2to.net 开源地址:https://github.com/dcdlove/JadeUI 预览DEMO下载: http://pa ...

  8. EF 记录执行的sql语句

    最近做了个中等的项目,数据不会很多,开发时间比较紧迫,所以用了EF的框架. 在使用过程中,发现有时候执行的结果不如预期,想看看执行的sql语句为何,遍查找资料,在网上找到了相关辅助类,拿来使用,部署到 ...

  9. ParallelsDesktop安装DOS7.1并与MAC共享文件

    ParallelsDesktop安装DOS7.1并与MAC共享文件 Table of Contents 1. 在Parallels Desktop中安装DOS7.1 2. 配置与Mac共享文件 1 在 ...

  10. mysql操作封装

    <?php//连接数据库function connect(){  $link = mysql_connect(DB_HOST,DB_USER,DB_PWD)or die("数据库连接失 ...