您的位置 首页 > 数码极客

【qqpy】一键生成 QQ 历史报告,谁最在意你?

门|孤鸟的来源| SegmentFault

编辑| EarlGrey推荐|编程公众号(codingpy)

最近几年微信流行,大多数人不再经常使用QQ,所以我们对自己的QQ数据不是特别了解。

我相信,如果能够生成一份属于自己的QQ历史报告,那将是无比开心的一件事。

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

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

功能截图

如何运行

  1. # 跳转到当前目录

  2. cd 目录名

  3. # 先卸载依赖库

  4. pip uninstall -y -r requirement.txt

  5. # 再重新安装依赖库

  6. pip install -r requirement.txt

  7. # 开始运行

  8. Python main.py

编写思路

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

  1. main.py,主程序,用于获取并处理相关数据,并导出数据报告。

  2. qq_bot.py, 核心模块,实现了qq相关的接口,较为复杂。

  3. ,绘制gui模块,使用tkinter绘制基本的交互界面。

  4. ,数据存储模块,所有数据采用base64编码存储。

main.py模块

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

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

  1. # 初始化文件夹

  2. init_folders

  3. # 写入项目所需资源文件到本地目录

  4. write_data


  5. # 创建一个自己编写的qq bot对象

  6. bot = Bot

  7. custom_print(u'登录成功,正在获取数据...')


  8. # 定义欲输出的markdown字符串

  9. markdown_content = '''

  10. <p align="center">

  11. <font size='6px'>{qq_number}的个人QQ历史报告</font>

  12. <img src="{qq_icon_png}" align="right" height="60">

  13. </p>

  14. '''

  15. # 更新一下欲输出的markdown文本

  16. markdown_content = markdown_con('{qq_number}',bot.qq_number)

  17. markdown_content = markdown_con('{qq_icon_png}', 'data;)

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

  1. custom_print(u'正在获取该登录账户的详细数据...')

  2. detail_information = bot.get_detail_information

  3. # content为markdown语法文本

  4. content = '\n<br/><br/>\n' + '## 我的详细资料\n' + '种类|内容\n:- | :-\n'

  5. for key, value in de:

  6. if key == 'qq_level':

  7. star_count, moon_count, sun_count, crown_count = calculate_level(value)

  8. data = crown_count * '!(data)' + sun_count * '!(data)' + moon_count * '!(data)' + star_count * '!(data)'

  9. content += '{}|{}\n'.format(key_dict[key], data)

  10. else:

  11. content += '{}|{}\n'.format(key_dict[key], value)

  12. # 更新一下欲输出的markdown文本

  13. markdown_content += content

  14. markdown_content += '\n> 注:单向好友表示他/她的列表中有你,而你的列表中没有他/她'

  15. # 每个步骤完成后,保存markdown文件,以便防止程序出错时能够保存到最新的数据

  16. with open('{}的个人QQ历史报告.md'.forma), 'w', encoding='utf-8') as file:

  17. (markdown_content)

接着,获取所有qq好友的备注名和qq号

  1. all_qq_friends = bot.get_all_friends_in_qq

  2. custom_print(u'所有qq好友号码和备注名中...')

  3. qq_number_list =

  4. for key, friend_group in all_qq_:

  5. for info in friend_group['mems']:

  6. qq_number_li(info['uin'])

并获取所有群数据

  1. # 获取所有群信息

  2. custom_print(u'获取该QQ加入的所有群信息...')

  3. group_list = bot.get_group

  4. print(group_list)

  5. # content为markdown语法文本

  6. content = '\n\n<br/><br/>\n' + '## 我加入的群资料\n' + '序号|群名|群号|群主QQ\n:- | :-| :-| :-\n'

  7. # 获取某个群的群成员信息

  8. for index, group in enumerate(group_list):

  9. group_number = group['gc']

  10. group_name = group['gn']

  11. owner = group['owner']

  12. content += '{}|{}|{}|{}\n'.format(str(index+1), str(group_name), str(group_number), str(owner))


  13. # 更新一下欲输出的markdown文本

  14. markdown_content += content

  15. # 每个步骤完成后,保存markdown文件,以便防止程序出错时能够保存到最新的数据

  16. with open('{}的个人QQ历史报告.md'.forma), 'w', encoding='utf-8') as file:

  17. (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登录为例:

  1. def login_id_qq_com(self):

  2. # 登录id.qq.com


  3. # 访问网页,为了获取参数pt_login_sig

  4. login_url = ';appid=1006102&daid=1&style=23&hide_border=1&proxy_url=;s_url=;

  5. html = get_html(login_url, '')

  6. # 对返回的cookies进行转化为dict类型,方便处理

  7. cookies_back_dict = dict_from_cookiejar)

  8. pt_login_sig = cookies_back_dict['pt_login_sig']

  9. (cookies_back_dict)


  10. # 访问网页,为了获取参数ptqrtoken

  11. qrcode_url = ';e=2&l=M&s=4&d=72&v=4&t=0.10239549811477189&daid=1&pt_3rd_aid=0'

  12. html = get_html(qrcode_url, '')

  13. # 对返回的cookies进行转化为dict类型,方便处理

  14. cookies_back_dict = dict_from_cookiejar)

  15. qrsig = cookies_back_dict['qrsig']

  16. ptqrtoken = hash33_token(qrsig)

  17. (cookies_back_dict)



  18. # 将二维码显示到图片框

  19. BytesIOObj = BytesIO

  20. By)

  21. qr_code = PIL.Image.open(BytesIOObj)

  22. image = PIL.ImageTk.PhotoImage(qr_code)

  23. image_label['image'] = image



  24. # 实时检测二维码状态

  25. while (True):

  26. # 目标网址

  27. target_url = ';ptqrtoken=' + str(ptqrtoken) + '&ptredirect=1&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-54&js_ver=19042519&js_type=1&login_sig=' + str(pt_login_sig) + '&pt_uistyle=40&aid=1006102&daid=1&'


  28. # 登录,需要带上访问cookies

  29. html = get_html(target_url, )


  30. # 返回的响应码为200说明二维码没过期

  31. if ):

  32. if ('二维码未失效' in ):

  33. custom_print(u'(1/3)登录id.qq.com中,当前二维码未失效,请你扫描二维码进行登录')

  34. elif ('二维码认证' in ):

  35. custom_print(u'(1/3)登录id.qq.com中,扫描成功,正在认证中')

  36. elif ('登录成功' in ):

  37. = True

  38. custom_print(u'(1/3)登录id.qq.com中,登录成功')

  39. break

  40. if ('二维码已经失效' in ):

  41. custom_print(u'(1/3)登录id.qq.com中,当前二维码已失效,请重启本软件')

  42. exit


  43. # 延时

  44. (2)


  45. # 登录成功后,把返回的cookies合并进去

  46. = dict_from_cookiejar)

  47. (cookies_back_dict)

  48. # print(u'当前cookies:{}'.format(cookies_merge_dict))


  49. # 获取此次登录的qq号码

  50. qq_list = re.findall(r'&uin=(.+?)&service', )

  51. = qq_list[0]



  52. # 登录成功后,会返回一个地址,需要对该地址进行访问以便获取新的返回cookies

  53. startIndex = ().find('http')

  54. endIndex = ().find('pt_3rd_aid=0')

  55. url = ()[startIndex:endIndex] + 'pt_3rd_aid=0'


  56. # 屏蔽https证书警告

  57. urllib3.disable_warnings


  58. # 这里需要注意的是,需要禁止重定向,才能正确获得返回的cookies

  59. html = get(url, cookies=, allow_redirects=False, verify=False)

  60. # 把返回的cookies合并进去

  61. cookies_back_dict = dict_from_cookiejar)

  62. (cookies_back_dict)

首先是访问指定网址,获取参数 pt_login_sig,其次是访问另外一个网址,获取参数qrsig,通过加密函数,将参数qrsig转化为ptqrtoken,然后就是获取二维码图片的状态了。当我们检测到登录成功时,就证明用户已经完成扫码操作,此时将网址返回的cookie保存下来。

这里要说明的是,加密函数的获取,需要具备一定的抓包基础才能获取得到。本程序的几个加密函数如下:

  1. # 对qrsig进行基本的加密,该加密函数由抓包获得,需要具备一定抓包知识才能找到该加密函数

  2. # 根据javascript版的加密函数,将其改写成python版本

  3. def hash33_token(t):

  4. e, n = 0, len(t)

  5. for i in range(0,n):

  6. e += (e << 5) + ord(t[i])

  7. return 2147483647 & e




  8. # 对skey进行基本的加密,该加密函数由抓包获得,需要具备一定抓包知识才能找到该加密函数

  9. # 根据javascript版的加密函数,将其改写成python版本

  10. def hash33_bkn(skey):

  11. e = skey

  12. t = 5381


  13. for n in range(0,len(e)):

  14. t += (t << 5) + ord(e[n])

  15. return 2147483647 & t

由于该模块下具有许多获取相关数据的qq接口,但是它们的形式非常相似,所以本节仅仅以获取所有qq群数据为例:

  1. def get_group(self):


  2. # 获取所有群基本信息

  3. # bkn由参数skey通过另一个加密函数得到

  4. bkn = hash33_bkn['skey'])

  5. submit_data = {'bkn': bkn}

  6. html = post_html(';, , submit_data)

  7. group_info = loads()

  8. print(group_info)

  9. return group_info['join']

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

tkinter_gui模块

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

static_data模块

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

补充

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

地址:

-- 完 --

回复下方「关键词」,获取优质资源

回复关键词「 pybook03」,立即获取主页君与小伙伴一起翻译的《Think Python 2e》电子版

回复关键词「pybooks02」,立即获取 O'Reilly 出版社推出的免费 Python 相关电子书合集

回复关键词「书单02」,立即获取主页君整理的 10 本 Python 入门书的电子版

印度小伙写了套深度学习教程,Github上星标已经5000+

GitHub热榜第四!这套Python机器学习课,免费获取还易吸收

《流畅的 Python》到底好在哪?

如何系统化学习 Python ?

GitHub标星2.6万!Python算法新手入门大全

使用 Vue.js 和 Flask 实现全栈单页面应用

Python 实现一个自动化翻译和替换的工具

使用 Python 制作属于自己的 PDF 电子书

12步轻松搞定Python装饰器

200 行代码实现 2048 游戏

题图:pexels,CC0 授权。

关于作者: admin

无忧经验小编鲁达,内容侵删请Email至wohenlihai#qq.com(#改为@)

热门推荐