目錄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 * '![](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號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本項目