一鍵生成屬于自己的QQ歷史報(bào)告,看看你對(duì)自己的QQ了解程度有多深?

近年來(lái)穆律,由于微信的流行惠呼,幾乎所有的人都不再頻繁使用QQ,所以我們對(duì)自己的QQ數(shù)據(jù)并不是特別了解峦耘。我相信剔蹋,如果能夠制作屬于自己的QQ的歷史報(bào)告的話,那是再好不過(guò)的快樂(lè)的事情了辅髓。

目前QQ的數(shù)據(jù)分析工具很少泣崩,原因是QQ相關(guān)的界面更加復(fù)雜。**程序的操作非常簡(jiǎn)單洛口,用戶交互界面很好矫付,只需要掃描代碼的一步操作

目前,本程序獲得的數(shù)據(jù)包括:QQ詳細(xì)數(shù)據(jù)第焰、手機(jī)在線時(shí)間买优、非隱形在線時(shí)間、QQ活動(dòng)時(shí)間挺举、單向朋友號(hào)杀赢、QQ屬性分析、我在過(guò)去一年中退出的群聊數(shù)據(jù)湘纵、我刪除的一個(gè)月的朋友數(shù)據(jù)脂崔、所有支付信息、我最關(guān)心的人和最關(guān)心我的人梧喷。由于相關(guān)數(shù)據(jù)接口的訪問(wèn)限制砌左,因此本程序不分析QQ好友

功能截圖

如何運(yùn)行

# 跳轉(zhuǎn)到當(dāng)前目錄
cd 目錄名
# 先卸載依賴庫(kù)
pip uninstall -y -r requirement.txt
# 再重新安裝依賴庫(kù)
pip install -r requirement.txt
# 開始運(yùn)行
python main.py

編寫思路

本程序分為多個(gè)模塊脖咐,模塊如下:

  1. main.py,主程序汇歹,用于獲取并處理相關(guān)數(shù)據(jù)文搂,并導(dǎo)出數(shù)據(jù)報(bào)告。
  2. qq_bot.py秤朗, 核心模塊,實(shí)現(xiàn)了qq相關(guān)的接口笔喉,較為復(fù)雜取视。
  3. tkinter_gui.py,繪制gui模塊常挚,使用tkinter繪制基本的交互界面作谭。
  4. static_data.py,數(shù)據(jù)存儲(chǔ)模塊奄毡,所有數(shù)據(jù)采用base64編碼存儲(chǔ)折欠。

main.py模塊

首先,初始化相關(guān)文件夾吼过,并調(diào)用qq_bot.py模塊锐秦,定義一個(gè)qq bot對(duì)象,該對(duì)象為本程序的核心對(duì)象盗忱,所有數(shù)據(jù)獲取均從該對(duì)象獲取酱床。
同時(shí),本程序數(shù)據(jù)的報(bào)告文件為.md格式

'''
遇到問(wèn)題沒(méi)人解答趟佃?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:766545907
尋找有志同道合的小伙伴扇谣,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書!
'''
    # 初始化文件夾
    init_folders()
    # 寫入項(xiàng)目所需資源文件到本地目錄
    write_data()

    # 創(chuàng)建一個(gè)自己編寫的qq bot對(duì)象
    bot = Bot()
    custom_print(u'登錄成功,正在獲取數(shù)據(jù)...')

    # 定義欲輸出的markdown字符串
    markdown_content = '''
    <p align="center">
    <font size='6px'>{qq_number}的個(gè)人QQ歷史報(bào)告</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')

登錄成功后闲昭,開始獲取該登錄賬戶的詳細(xì)資料

    custom_print(u'正在獲取該登錄賬戶的詳細(xì)數(shù)據(jù)...')
    detail_information = bot.get_detail_information()
    # content為markdown語(yǔ)法文本
    content = '\n<br/><br/>\n' + '## 我的詳細(xì)資料\n' + '種類|內(nèi)容\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> 注:?jiǎn)蜗蚝糜驯硎舅?她的列表中有你罐寨,而你的列表中沒(méi)有他/她'
    # 每個(gè)步驟完成后,保存markdown文件序矩,以便防止程序出錯(cuò)時(shí)能夠保存到最新的數(shù)據(jù)
    with open('{}的個(gè)人QQ歷史報(bào)告.md'.format(bot.qq_number), 'w', encoding='utf-8') as file:
        file.write(markdown_content)

接著鸯绿,獲取所有qq好友的備注名和qq號(hào)

    all_qq_friends = bot.get_all_friends_in_qq()
    custom_print(u'所有qq好友號(hào)碼和備注名中...')
    qq_number_list = []
    for key, friend_group in all_qq_friends.items():
        for info in friend_group['mems']:
            qq_number_list.append(info['uin'])

并獲取所有群數(shù)據(jù)

'''
遇到問(wèn)題沒(méi)人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:766545907
尋找有志同道合的小伙伴簸淀,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書楞慈!
'''
    # 獲取所有群信息
    custom_print(u'獲取該QQ加入的所有群信息...')
    group_list = bot.get_group()
    print(group_list)
    # content為markdown語(yǔ)法文本
    content = '\n\n<br/><br/>\n' + '## 我加入的群資料\n' + '序號(hào)|群名|群號(hào)|群主QQ\n:- | :-| :-| :-\n'
    # 獲取某個(gè)群的群成員信息
    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
    # 每個(gè)步驟完成后,保存markdown文件啃擦,以便防止程序出錯(cuò)時(shí)能夠保存到最新的數(shù)據(jù)
    with open('{}的個(gè)人QQ歷史報(bào)告.md'.format(bot.qq_number), 'w', encoding='utf-8') as file:
        file.write(markdown_content)

接下來(lái)的步驟如你所需囊蓝,也就是獲取其他相關(guān)的數(shù)據(jù),所以本小節(jié)就不一一詳細(xì)解釋了令蛉,您可以查看相關(guān)源代碼查看聚霜。獲取的數(shù)據(jù)包括:

  1. 獲取過(guò)去30天內(nèi)退出的群名單
  2. 獲取過(guò)去364天內(nèi)刪除的好友名單
  3. 判斷此次登錄的qq是否為vip或者svip
  4. 獲取qb值
  5. 獲取代付信息
  6. 親密度排行榜
  7. 共同好友數(shù)
  8. 成為好友的天數(shù)

qq_bot模塊

此模塊實(shí)現(xiàn)了獲取qq數(shù)據(jù)的接口狡恬,主要通過(guò)抓包獲得數(shù)據(jù)、分析數(shù)據(jù)蝎宇,對(duì)參數(shù)進(jìn)行加密解密等弟劲。

首先,是模擬掃碼登錄id.qq.com姥芥,qun.qq.com兔乞,qzone.qq.com。三者登錄方式大同小異凉唐,唯一有區(qū)別的就是提交數(shù)據(jù)中的參數(shù)加密方式不同庸追。
我們以id.qq.com登錄為例:

'''
遇到問(wèn)題沒(méi)人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:766545907
尋找有志同道合的小伙伴台囱,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書淡溯!
'''
    def login_id_qq_com(self):
        # 登錄id.qq.com

        # 訪問(wèn)網(wǎng)頁(yè),為了獲取參數(shù)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, '')
        # 對(duì)返回的cookies進(jìn)行轉(zhuǎn)化為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)

        # 訪問(wèn)網(wǎng)頁(yè)咱娶,為了獲取參數(shù)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, '')
        # 對(duì)返回的cookies進(jìn)行轉(zhuǎn)化為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

        # 實(shí)時(shí)檢測(cè)二維碼狀態(tài)
        while (True):
            # 目標(biāo)網(wǎng)址
            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&'

            # 登錄强品,需要帶上訪問(wèn)cookies
            html = get_html(target_url, self.cookies_merge_dict_in_id_qq_com)

            # 返回的響應(yīng)碼為200說(shuō)明二維碼沒(méi)過(guò)期
            if (html.status_code):
                if ('二維碼未失效' in html.text):
                    custom_print(u'(1/3)登錄id.qq.com中膘侮,當(dāng)前二維碼未失效,請(qǐng)你掃描二維碼進(jìn)行登錄')
                elif ('二維碼認(rèn)證' in html.text):
                    custom_print(u'(1/3)登錄id.qq.com中的榛,掃描成功喻喳,正在認(rèn)證中')
                elif ('登錄成功' in html.text):
                    self.is_login = True
                    custom_print(u'(1/3)登錄id.qq.com中,登錄成功')
                    break
                if ('二維碼已經(jīng)失效' in html.text):
                    custom_print(u'(1/3)登錄id.qq.com中困曙,當(dāng)前二維碼已失效表伦,請(qǐng)重啟本軟件')
                    exit()

            # 延時(shí)
            time.sleep(2)

        # 登錄成功后,把返回的cookies合并進(jìn)去
        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'當(dāng)前cookies:{}'.format(cookies_merge_dict))

        # 獲取此次登錄的qq號(hào)碼
        qq_list = re.findall(r'&uin=(.+?)&service', html.text)
        self.qq_number = qq_list[0]

        # 登錄成功后慷丽,會(huì)返回一個(gè)地址蹦哼,需要對(duì)該地址進(jìn)行訪問(wèn)以便獲取新的返回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合并進(jìn)去
        cookies_back_dict = dict_from_cookiejar(html.cookies)
        self.cookies_merge_dict_in_id_qq_com.update(cookies_back_dict)

首先是訪問(wèn)指定網(wǎng)址纲熏,獲取參數(shù)pt_login_sig,其次是訪問(wèn)另外一個(gè)網(wǎng)址锄俄,獲取參數(shù)qrsig局劲,通過(guò)加密函數(shù),將參數(shù)qrsig轉(zhuǎn)化為ptqrtoken奶赠,然后就是獲取二維碼圖片的狀態(tài)了鱼填。當(dāng)我們檢測(cè)到登錄成功時(shí),就證明用戶已經(jīng)完成掃碼操作毅戈,此時(shí)將網(wǎng)址返回的cookie保存下來(lái)苹丸。

這里要說(shuō)明的是愤惰,加密函數(shù)的獲取,需要具備一定的抓包基礎(chǔ)才能獲取得到赘理。本程序的幾個(gè)加密函數(shù)如下:

# 對(duì)qrsig進(jìn)行基本的加密宦言,該加密函數(shù)由抓包獲得,需要具備一定抓包知識(shí)才能找到該加密函數(shù)
# 根據(jù)javascript版的加密函數(shù)商模,將其改寫成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

# 對(duì)skey進(jìn)行基本的加密奠旺,該加密函數(shù)由抓包獲得,需要具備一定抓包知識(shí)才能找到該加密函數(shù)
# 根據(jù)javascript版的加密函數(shù)施流,將其改寫成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

由于該模塊下具有許多獲取相關(guān)數(shù)據(jù)的qq接口响疚,但是它們的形式非常相似,所以本節(jié)僅僅以獲取所有qq群數(shù)據(jù)為例:

    def get_group(self):

        # 獲取所有群基本信息
        # bkn由參數(shù)skey通過(guò)另一個(gè)加密函數(shù)得到
        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']

這里主要涉及到的還是參數(shù)的加密嫂沉、解密過(guò)程,這是一個(gè)難點(diǎn)扮碧,其他的話還是比較簡(jiǎn)單的趟章。

tkinter_gui模塊

這個(gè)模塊是繪制基本的gui模塊,采用python內(nèi)置的tkinter模塊完成慎王,用法相當(dāng)簡(jiǎn)單蚓土,這里就不詳細(xì)講了。

static_data模塊

這個(gè)模塊主要是用來(lái)存儲(chǔ)相關(guān)的數(shù)據(jù)的赖淤,在程序每次運(yùn)行時(shí)蜀漆,將該靜態(tài)資源文件輸出。這么做的原因是可以防止用戶將某些靜態(tài)數(shù)據(jù)給刪除了咱旱,導(dǎo)致程序運(yùn)行錯(cuò)誤确丢。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吐限,隨后出現(xiàn)的幾起案子鲜侥,更是在濱河造成了極大的恐慌,老刑警劉巖诸典,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件描函,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡狐粱,警方通過(guò)查閱死者的電腦和手機(jī)舀寓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)肌蜻,“玉大人互墓,你說(shuō)我怎么就攤上這事〗眩” “怎么了轰豆?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵胰伍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我酸休,道長(zhǎng)骂租,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任斑司,我火速辦了婚禮渗饮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宿刮。我一直安慰自己互站,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布僵缺。 她就那樣靜靜地躺著胡桃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪磕潮。 梳的紋絲不亂的頭發(fā)上翠胰,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音自脯,去河邊找鬼之景。 笑死,一個(gè)胖子當(dāng)著我的面吹牛膏潮,可吹牛的內(nèi)容都是我干的锻狗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼焕参,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼轻纪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起叠纷,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤桐磁,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后讲岁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體我擂,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年缓艳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了校摩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡阶淘,死狀恐怖衙吩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情溪窒,我是刑警寧澤坤塞,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布冯勉,位于F島的核電站,受9級(jí)特大地震影響摹芙,放射性物質(zhì)發(fā)生泄漏灼狰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一浮禾、第九天 我趴在偏房一處隱蔽的房頂上張望交胚。 院中可真熱鬧,春花似錦盈电、人聲如沸蝴簇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)熬词。三九已至,卻和暖如春吸重,著一層夾襖步出監(jiān)牢的瞬間互拾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工晤锹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摩幔,地道東北人彤委。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓鞭铆,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親焦影。 傳聞我的和親對(duì)象是個(gè)殘疾皇子车遂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容