標籤:

抓取60000+QQ空間說說做一次數據分析

對於QQ空間的數據一直來是垂涎不已,老早就想偷過來研究研究,這幾天閑下來便開始動手。。。

整個程序的流程為:登錄-->獲取cookie-->獲取所有的好友qq_number-->根據所有的好友qq遍歷他們的說說-->get所有好友的說說數據

程序跑了20多分鐘就跑完了,,共282好友,,跑了60000+說說

有些個人隱私我抹掉了。。甭介意。嘿嘿

1.登錄-->獲取cookie

打開i.qq.com/,如下圖

但大多數時候是這樣的

我們這裡使用賬號密碼登錄,為了方便使用selenium自動化神器(關於selenium的用法可以參考my.oschina.net/u/326469,這裡不做過多闡述)

QQ賬號,QQ密碼存儲在userinfo.ini文件中,然後用configparser將其讀取出來

讀取的代碼如下

configparser是一個讀取配置文件的庫,這裡讀取的格式為get([配置文件中括弧里的值],『相對應的key值』)

import configparsernconfig = configparser.ConfigParser(allow_no_value=False)nconfig.read(userinfo.ini)nself.__username =config.get(qq_info,qq_number)nself.__password=config.get(qq_info,qq_password)n

用戶信息讀取出來後就可以登錄了

有些盆友用selenium的時候,可能會發現有些元素定位不到,這是因為有些網頁套了一個iFrame

selenium根據id定位到該iframe

self.web.switch_to_frame(login_frame)n

自動登錄且獲取cookie的代碼

def login(self):n self.web.switch_to_frame(login_frame)n log=self.web.find_element_by_id("switcher_plogin")n log.click()n time.sleep(1)n username=self.web.find_element_by_id(u)n username.send_keys(self.__username)n ps=self.web.find_element_by_id(p)n ps.send_keys(self.__password)n btn=self.web.find_element_by_id(login_button)n time.sleep(1)n btn.click()n time.sleep(2)n self.web.get(https://user.qzone.qq.com/{}.format(self.__username))n cookie= for elem in self.web.get_cookies():n cookie+=elem["name"]+"="+ elem["value"]+";"n self.cookies=cookien self.get_g_tk()n self.headers[Cookie]=self.cookiesn self.web.quit()n

2.獲取所有好友的QQ_number

研究好久後發現在QQ空間主頁中許可權設置頁面中,點擊僅限QQ好友,會有下面這樣的頁面出來

按F12後研究js文件發現有這樣一個文件

這個js文件里有好友的qq_number

於是請求這個文件得到qq_number

def get_frends_url(self):n url=https://h5.qzone.qq.com/proxy/domain/base.qzone.qq.com/cgi-bin/right/get_entryuinlist.cgi?n params = {"uin": self.__username,n "fupdate": 1,n "action": 1,n "g_tk": self.g_tk}n url = url + parse.urlencode(params)n return urlnn def get_frends_num(self):n t=Truen offset=0n url=self.get_frends_url()n while(t):n url_=url+&offset=+str(offset)n page=self.req.get(url=url_,headers=self.headers)n if ""uinlist":[]" in page.text:n t=False else:nn if not os.path.exists("./frends/"):n os.mkdir("frends/")n with open(./frends/+str(offset)+.json,w,encoding=utf-8) as w:n w.write(page.text)n offset += 50n

這裡有一個函數self.g_tk()它返回一個加密的p_skey , 在這個js文件中qzfl_v8_2.1.61.js,有這樣一段代碼

QZFL.pluginsDefine.getACSRFToken = function(url) {n url = QZFL.util.URI(url);n var skey;n if (url) {n if (url.host && url.host.indexOf("qzone.qq.com") > 0) {n try {n skey = parent.QZFL.cookie.get("p_skey");n } catch (err) {n skey = QZFL.cookie.get("p_skey");n }n } else {n if (url.host && url.host.indexOf("qq.com") > 0) {n skey = QZFL.cookie.get("skey");n }n }n }n if (!skey) {n skey = QZFL.cookie.get("p_skey") || (QZFL.cookie.get("skey") || (QZFL.cookie.get("rv2") || ""));n }n return arguments.callee._DJB(skey);n };n QZFL.pluginsDefine.getACSRFToken._DJB = function(str) { var hash = 5381;n for (var i = 0, len = str.length;i < len;++i) {n hash += (hash << 5) + str.charCodeAt(i);n }n return hash & 2147483647;n };n

把它寫成python版的如下

def get_g_tk(self):n p_skey = self.cookies[self.cookies.find(p_skey=)+7: self.cookies.find(;, self.cookies.find(p_skey=))]n h=5381 for i in p_skey:n h+=(h<<5)+ord(i)n print(g_tk,h&2147483647)n self.g_tk=h&2147483647 n

因為將好友信息存儲為json文件,因此需要解析文件信息

#coding:utf-8 import jsonnimport osndef get_Frends_list():n k = 0n file_list=[i for i in os.listdir(./frends/) if i.endswith(json)]n frends_list=[]n for f in file_list:n with open(./frends/{}.format(f),r,encoding=utf-8) as w:n data=w.read()[95:-5]n js=json.loads(data)n # print(js) for i in js:n k+=1n frends_list.append(i)n return frends_listnnnfrends_list=get_Frends_list()nprint(frends_list)n

3.獲取所有好友說說

與之前類似,進入好友的說說主頁後發現也有這樣一個js文件將所有說說以json形式顯示出來

類似的,寫了獲取說說的代碼(經過測試,參數中的num最好寫20,否則會出現未知的結果。。。)

def get_mood_url(self):n url=https://h5.qzone.qq.com/proxy/domain/taotao.qq.com/cgi-bin/emotion_cgi_msglist_v6?n params = {n "sort":0,n "start":0,n "num":20,n "cgi_host": "http://taotao.qq.com/cgi-bin/emotion_cgi_msglist_v6",n "replynum":100,n "callback":"_preloadCallback",n "code_version":1,n "inCharset": "utf-8",n "outCharset": "utf-8",n "notice": 0,n "format":"jsonp",n "need_private_comment":1,n "g_tk": self.g_tkn }n url = url + parse.urlencode(params)n return urlnnn def get_mood_detail(self): from getFrends import frends_listn url = self.get_mood_url()n for u in frends_list[245:]:n t = Truen QQ_number=u[data]n url_ = url + &uin= + str(QQ_number)n pos = 0 while (t):n url__ = url_ + &pos= + str(pos)n mood_detail = self.req.get(url=url__, headers=self.headers)n print(QQ_number,u[label],pos)n if ""msglist":null" in mood_detail.text or ""message":"對不起,主人設置了保密,您沒有許可權查看"" in mood_detail.text:n t = False else:n if not os.path.exists("./mood_detail/"):n os.mkdir("mood_detail/")n if not os.path.exists("./mood_detail/"+u[label]):n os.mkdir("mood_detail/"+u[label])n with open(./mood_detail/+u[label]+"/" +str(QQ_number)+"_"+ str(pos) + .json, w,encoding=utf-8) as w:n w.write(mood_detail.text)n pos += 20n time.sleep(2)n

將需要的說說數據存入資料庫

#存入資料庫 def dataToMysql():n con=pymysql.connect(n host=127.0.0.1,n user=root,n password="×××",n database=qq_z,n port=3306,n )n cur=con.cursor()n sql="insert into info (qq_number,created_time,content,commentlist,source_name,cmtnum,name) values ({},{},{},{},{},{},{});"nn d=[i for i in os.listdir(mood_detail) if not i.endswith(.xls)]n for ii in d:n fl=[i for i in os.listdir(mood_detail/+ii) if i.endswith(.json)]n print(mood_detail/+ii)n k=1 for i in fl:n with open(mood_detail/+ii+"/"+i,r,encoding=latin-1) as w:n s=w.read()[17:-2]n js=json.loads(s)n print(i)n for s in js[msglist]:n m=-1 if not s[commentlist]:n s[commentlist]=list()n cur.execute(sql.format(int(i[:i.find(_)]),s[created_time],str(s[content]),str([(x[content],x[createTime2],x[name],x[uin]) for x in list(s[commentlist])]),str(s[source_name]),int(s[cmtnum]),str(s[name])))n k+=1n con.commit()n con.close()n

將需要的說說數據存入Excel

def dataToExcel():n d=[i for i in os.listdir(mood_detail) if not i.endswith(.xls)]n for ii in d:n wb=xlwt.Workbook()n sheet=wb.add_sheet(sheet1,cell_overwrite_ok=True)n sheet.write(0,0,content)n sheet.write(0,1,createTime)n sheet.write(0,2,commentlist)n sheet.write(0,3,source_name)n sheet.write(0,4,cmtnum)n fl=[i for i in os.listdir(mood_detail/+ii) if i.endswith(.json)]n print(mood_detail/+ii)n k=1 for i in fl:n with open(mood_detail/+ii+"/"+i,r,encoding=latin-1) as w:n s=w.read()[17:-2]n js=json.loads(s)n print(i)n for s in js[msglist]:n m=-1n sheet.write(k,m+1,str(s[content]))n sheet.write(k,m+2,str(s[createTime]))n if not s[commentlist]:n s[commentlist]=list()n sheet.write(k,m+3,str([(x[content],x[createTime2],x[name],x[uin]) for x in list(s[commentlist])]))n sheet.write(k,m+4,str(s[source_name]))n sheet.write(k,m+5,str(s[cmtnum]))n k+=1 if not os.path.exists(mood_detail/Excel/):n os.mkdir(mood_detail/Excel/)n try:n wb.save(mood_detail/Excel/+ii+.xls)n except Exception:n print("error")n

4.分析數據

24小時發布的說說數

大家在中午和晚上發布的說說比較多,凌晨比較少

說說最多排行top20

說說最少排行top20

果然,,悶騷的人發的說說比較多。。。哈哈哈

從2000年到2018年,說說分布如下

看來我的朋友們年輕的時候蠻悶騷,,隨著年紀增大,,說說越來越少。。

感謝zhuanlan.zhihu.com/p/24給我的提示。。。少走了許多彎路

數據抓取速度賊快,,20分鐘抓取了我所有好友(282+)60000+說說。。

項目已傳到

碼雲 : git.oschina.net/nanxun/

github : github.com/nanxung/QQ_z

朋友們,覺得有用來個star噢。。蟹蟹。。。


推薦閱讀:

Spider與OpenPyXL的結合
PyQt5系列教程(14):複選框

TAG:Python教程 |