Python爬蟲實戰,DecryptLogin模組,Python模擬登入之生成QQ個人專屬報告
前言
這次我們藉助自己開源的DecryptLogin庫做一件有趣的事,生成QQ個人專屬報告。
就是把QQ中和自己相關的資料爬取下來並進行視覺化~
開發工具
** Python版本:**3.6.4
** 相關模組:**
DecryptLogin模組;
wordcloud模組;
requests模組;
pillow模組;
以及一些python自帶的模組。
環境搭建
安裝Python並新增到環境變數,pip安裝需要的相關模組即可。
原理簡介
這裡我們簡單介紹一下實現原理。首先,我們需要藉助自己開源的庫來實現模擬登入QQ空間,QQ群以及我的QQ中心。
而QQ群和我的QQ中心的模擬登入原理和QQ空間大同小異,這裡就不再贅述了啊,對了,庫的安裝方式參見很久以前的文章:
這裡我們來著重講一講QQ個人資料爬取部分的原理。最基本的自然是我們自己填寫的個人資訊啦,這個在我的QQ中心可以找到,比如:
通過抓包分析,我們可以發現以下連結包含了我們需要的資訊:
當然還有其他一些連結。感興趣的小夥伴可以自己再找找。觀察這些請求需要攜帶的引數:
請求上圖userinfo那個連結需要攜帶的引數: ldw: 497****************b1f3611dba60b802*******1268dac r: 0.3504175608072273 請求上圖summary那個連結需要攜帶的引數: ldw: 497****************b1f3611dba60b802*******1268dac r: 0.502514472265531
我們很容易發現,請求這些連結都需要攜帶兩個引數,即:
ldw:不知道是啥玩意。
r:看著就像是隨機數。
測試後發現ldw這個引數並不是固定不變的,那我們應該如何計算這個引數呢?全域性搜尋一下,可以發現一個計算ldw的函式:
乍一眼看,這是啥玩意啊T_T。好像不好算?別急,作為新時代熟讀兵法的優秀少年,應該懂得“借刀殺人”的道理。我們再仔細看看ldw到底是啥,找到相關的js檔案,可以發現一個註釋:
搜一下有沒有相關的運算,結果發現了這個:
藉助註釋,合理猜測一下ldw的值可能可以用bkn的值代替,bkn很好算,js程式碼一目瞭然。試著驗證一下,竟然真的可以T_T。於是我們就可以抓取到個人的基本資訊了,程式碼實現如下:
'''獲取登入賬戶的個人資料'''
def getPersonalInfo(self, filename='personal_info.pkl'):
personal_info = dict()
summary_url = 'https://id.qq.com/cgi-bin/summary?'
userinfo_url = 'https://id.qq.com/cgi-bin/userinfo?'
bkn = self.__skey2bkn(self.session_id_all_cookies['skey'])
params = {
'r': str(random.random()),
'ldw': str(bkn)
}
headers = {
'referer': 'https://id.qq.com/myself/myself.html?ver=10049&',
'accept': '*/*',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
'cache-control': 'no-cache',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
res = self.session_id.get(summary_url, headers=headers, params=params, verify=False)
res.encoding = 'utf-8'
personal_info.update(res.json())
params = {
'r': str(random.random()),
'ldw': str(bkn)
}
headers = {
'referer': 'https://id.qq.com/myself/myself.html?ver=10045&',
'accept': '*/*',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
'cache-control': 'no-cache',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
while True:
res = self.session_id.get(userinfo_url, headers=headers, params=params, verify=False)
res.encoding = 'utf-8'
if res.text:
break
personal_info.update(res.json())
personal_info_parsed = {
'暱稱': personal_info['nick'],
'出生日期': '-'.join([str(personal_info['bir_y']), str(personal_info['bir_m']).zfill(2), str(personal_info['bir_d']).zfill(2)]),
'年齡': personal_info['age'],
'Q齡': personal_info['qq_age'],
'賬號等級': personal_info['level'],
'等級排名': personal_info['level_rank'],
'好友數量': personal_info['friend_count'],
'單向好友數量': personal_info['odd_count'],
'已備註好友數量': personal_info['remark_count'],
'好友分組數量': personal_info['group_count'],
'最近聯絡人數量': personal_info['chat_count'],
'工作': personal_info['work'],
'個性簽名': personal_info['commt']
}
saveData2Pkl(personal_info_parsed, os.path.join(self.dirpath, filename))
return personal_info_parsed
然後利用抓取的個人資訊,我們可以製作一張簡易的QQ名片,效果參見效果展示部分。
接下來,我們看看能不能抓取點其他資料。比如所有的QQ好友資料?通過觀察,發現這些資料可以在QQ群官網裡找到:
請求這個連結需要的引數是bkn,這個我們前面已經說過怎麼算了,所以就直接上程式碼啦(這裡我們只能獲取暱稱和QQ號,好友的詳細資訊是無法獲取的,這個以後有機會再搞吧):
'''抓取QQ好友資料'''
def getQQFriendsInfo(self, filename='friends_info.pkl'):
friends_info = dict()
get_friend_list_url = 'https://qun.qq.com/cgi-bin/qun_mgr/get_friend_list'
bkn = self.__skey2bkn(self.session_qun_all_cookies['skey'])
data = {'bkn': bkn}
headers = {
'referer': 'https://qun.qq.com/member.html',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
res = self.session_qun.post(get_friend_list_url, data=data, verify=False, headers=headers)
for key, value in res.json()['result'].items():
for mem in value['mems']:
qq_number = mem['uin']
nickname = mem['name']
friends_info[qq_number] = [nickname]
saveData2Pkl(friends_info, os.path.join(self.dirpath, filename))
return friends_info
然後將所有好友的暱稱做個詞雲?效果還是效果展示部分(隱私問題,我進行了模糊處理)。
最後再獲取一些最近的操作資訊唄,比如最近30天退出的群,最近一年刪除的好友,以及最近我關心誰,最近誰關心我等等,原理和之前差不多,就不贅述了,程式碼實現如下:
'''獲取近期的操作資料'''
def getRecentOperationsInfo(self, filename='recent_operation_info.pkl'):
recent_operation_info = dict()
bkn = self.__skey2bkn(self.session_qun_all_cookies['skey'])
# 近30天退出的群
data = {'bkn': bkn}
headers = {
'accept': 'application/json, text/javascript, */*; q=0.01',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'origin': 'https://huifu.qq.com',
'referer' : 'https://huifu.qq.com/recovery/index.html?frag=0',
'content-type': 'text/plain'
}
gr_grouplist_url = 'https://huifu.qq.com/cgi-bin/gr_grouplist'
res = self.session_qun.post(gr_grouplist_url, data=data, headers=headers, verify=False)
group_info = res.json()
recent_operation_info['過去30天我退出的群個數'] = len(group_info.get('ls', []))
recent_operation_info['過去30天我退出的群'] = []
if 'ls' in group_info.keys():
for key, value in group_info.items():
recent_operation_info['過去30天我退出的群'].append(value['n'])
# 近一年刪除的好友
params = {
'bkn': str(bkn),
'ts': str(int(time.time())),
'g_tk': str(bkn),
'data': '{"11053":{"iAppId":1,"iKeyType":1,"sClientIp":"","sSessionKey":"%s","sUin":"%s"}}' % (self.session_qun_all_cookies['skey'], self.username)
}
headers = {
'accept': 'application/json, text/javascript, */*; q=0.01',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'origin': 'https://huifu.qq.com',
'referer' : 'https://huifu.qq.com/recovery/index.html?frag=1',
'content-type': 'text/plain'
}
srfentry_url = 'https://proxy.vip.qq.com/cgi-bin/srfentry.fcgi?'
res = self.session_qun.get(srfentry_url, params=params, headers=headers, verify=False)
del_friend_list = res.json()['11053']['data']['delFriendList']
recent_operation_info['過去一年我刪除的好友個數'] = len(del_friend_list)
recent_operation_info['過去一年我刪除的好友'] = []
if len(del_friend_list) > 0:
recent_operation_info['過去一年我刪除的好友'] = del_friend_list['364']['vecUin']
# 誰在意我
bkn = self.__skey2bkn(self.session_zone_all_cookies['skey'])
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
res = self.session_zone.get('https://user.qzone.qq.com/%s' % self.username, verify=False, headers=headers)
qzonetoken = re.findall(r'{ try{return "(.+?)";', res.text)[0]
params = {
'uin': str(self.username),
'do': '2',
'rd': str(random.random()),
'fupdate': '1',
'clean': '0',
'g_tk': str(bkn),
'qzonetoken': str(qzonetoken)
}
ship_url = 'https://rc.qzone.qq.com/proxy/domain/r.qzone.qq.com/cgi-bin/tfriend/friend_ship_manager.cgi?'
res = self.session_zone.get(ship_url, verify=False, headers=headers, params=params)
text = (res.text).replace('_Callback(','')
who_care_me = json.loads(text[:len(text)-2])['data']['items_list']
if len(who_care_me) > 5:
who_care_me = who_care_me[:5]
recent_operation_info['誰在意我'] = [[each['uin'], each['score']] for each in who_care_me]
# 我在意誰
params = {
'uin': str(self.username),
'do': '1',
'rd': str(random.random()),
'fupdate': '1',
'clean': '1',
'g_tk': str(bkn),
'qzonetoken': str(qzonetoken)
}
res = self.session_zone.get(ship_url, verify=False, headers=headers, params=params)
text = (res.text).replace('_Callback(','')
i_care_who = json.loads(text[:len(text)-2])['data']['items_list']
if len(i_care_who) > 5:
i_care_who = i_care_who[:5]
recent_operation_info['我在意誰'] = [[each['uin'], each['score']] for each in i_care_who]
saveData2Pkl(recent_operation_info, os.path.join(self.dirpath, filename))
return recent_operation_info
然後和前面一樣,也做個卡片吧~效果還是參見效果展示部分。
OK,為了避免推文的時候又比較晚T_T,今天就到這吧~完整原始碼詳見相關檔案。
效果展示
這裡把抓取到的資料進行視覺化。
1. QQ名片
2.好友暱稱詞雲
3. 我的近期操作
文章到這裡就結束了,感謝你的觀看,關注我每天分享Python模擬登入系列,下篇文章分享下載B站指定UP主的所有視訊
為了感謝讀者們,我想把我最近收藏的一些程式設計乾貨分享給大家,回饋每一個讀者,希望能幫到你們。
乾貨主要有:
① 2000多本Python電子書(主流和經典的書籍應該都有了)
② Python標準庫資料(最全中文版)
③ 專案原始碼(四五十個有趣且經典的練手專案及原始碼)
④ Python基礎入門、爬蟲、web開發、大資料分析方面的視訊(適合小白學習)
⑤ Python學習路線圖(告別不入流的學習)
⑥ 兩天的Python爬蟲訓練營直播許可權
All done~完整原始碼+乾貨詳見個人簡介或者私信獲取相關檔案。。