QQ空間動態爬蟲

先說明幾件事:

  • 題目的意思是,用於獲取「QQ空間動態」的爬蟲,而不是」針對QQ空間「的」動態爬蟲「
  • 這裡的QQ空間動態,特指「說說」

  • 程序是使用cookie登錄的。所以如果是想知道如何使用爬蟲根據QQ號和密碼來實現登錄的朋友可以把頁面關了
  • 本程序用python3實現,具體版本為python3.5,唯一需要用到的第三方庫是requests

  • 程序代碼獲取方式在最後面

----------------------------------------

程序主要由三部分構成,它們分別對應著本爬蟲的三個步驟。

  1. 獲取所有QQ好友信息

    間接獲取。先把QQ空間的訪問許可權設置為僅QQ好友可訪問

    點保存後,上方會出現「當前許可權下,XXX好友可以訪問你的空間」的提示,如上圖。此時打開F12,切換到JavaScript監測窗口。點擊上圖中畫下劃線的那幾個字,就可以發現瀏覽器發送了一個GET請求,在Firebug中看到是這樣的:

    查看它的response,會發現裡面就是由自己好友的名字和QQ號碼組成的近似於JSON格式的內容。爬蟲程序中的get_my_friends.py就是用於獲取它的內容的,其主要代碼如下:

    def get_friends(self): key = True position = 0 while key: url = self.base_url + "&offset=" + str(position) referer = "http://qzs.qq.com/qzone/v8/pages/setting/visit_v8.html" self.headers["Referer"] = referer print(" Dealing with position %d." % position) res = requests.get(url, headers=self.headers) html = res.text with open("friends/offset" + str(position) + ".json", "w") as f: f.write(html) # 檢查是否已經全部都獲取完,如果是的話 # uinlist對應的是一個空列表 with open("friends/offset" + str(position) + ".json") as f2: con = f2.read() if """"uinlist":[]""" in con: print("Get friends Finish") break position += 50

  2. 獲取所有好友的QQ號碼

這一步其實只是文本處理,或者說是字元串處理而已。把上一步中保存好的文件進行處理,從中提取好友的QQ號碼和名稱,將其保存在一個文件中(其名為qqnumber.inc)。由於其內容本身近於字典形式,所以稍加處理,將其轉成字典,再進行處理。處理程序為爬蟲程序中的get_qq_number.py,主要代碼如下:

def exact_qq_number(self): friendsFiles = [x for x in os.listdir("friends") if x.endswith("json")] qqnumber_item = [] i = 0 for each_file in friendsFiles: with open("friends/" + each_file) as f: source = f.read() con_dict = source[75:-4].replace("
", "") con_json = json.loads(con_dict) friends_list = con_json["uinlist"] # Get each item from friends list, each item is a dict for item in friends_list: i = i + 1 qqnumber_item.append(item) else: with open("qqnumber.inc", "w") as qqfile: qqfile.write(str(qqnumber_item))

3. 分別獲取每個好友的空間動態(說說)

獲取好友的說說,方法類似於第1步。先打開F12,保持在默認的All選項卡下就行。再打開好友的空間,點開他們的說說主頁,此時可以在請求列表中找到一個URL中包含emotion_cgi_msglist的請求,根據名字就可以猜到,它就是我們要的信息了。然後我們可以模擬這個請求,獲取返回的內容並保存。爬蟲程序中的get_moods.py就用於此。

此程序文件中包含兩個類:Get_moods_start()、Get_moods()。後者實現發送HTTP請求並獲取返回內容、保存內容,前者用於把QQ號傳到後者的方法中進行處理、控制循環、處理異常。Get_moods()功能實現的主要方法代碼如下:

def get_moods(self, qqnumber): """Use cookie and header to get moods file and save it to result folder with QQnumber name""" referer = "http://user.qzone.qq.com/" + qqnumber self.headers["Referer"] = referer # Create a folder with qq number to save it"s result file util.check_path("mood_result/" + qqnumber) # Get the goal url, except the position argument. url_base = util.parse_moods_url(qqnumber) pos = 0 key = True while key: print(" Dealing with position: %d" % pos) url = url_base + "&pos=%d" % pos res = self.session.get(url, headers = self.headers) con = res.text with open("mood_result/" + qqnumber + "/" + str(pos), "w") as f: f.write(con) if """"msglist":null""" in con: key = False # Cannot access... if """"msgnum":0""" in con: with open("crawler_log.log", "a") as log_file: log_file.write("%s Cannot access..
" % qqnumber) key = False # Cookie expried if """"subcode":-4001""" in con: with open("crawler_log.log", "a") as log_file: log_file.write("Cookie Expried! Time is %s
" % time.ctime()) sys.exit() pos += 20 time.sleep(5)

程序運行的結果會保存在名為mood_result的文件夾中,其中包含以各好友QQ號碼為名的文件夾,他們的說說信息文件都保存在對應的文件夾中。

-----------------------------------------

其它說明

程序還有兩個文件,util.py和main.py,後者是程序運行的入口,前者則包含了一些通用功能,例如獲取cookie、生成發送HTTP請求時要用到的g_tk值、構造URL。此處講一下g_tk值。

在前面第1步和第3步中,發送的HTTP請求的URL參數裡面,都包含有g_tk值,這個值是通過cookie中的p_skey參數的值生成的。可以在登錄QQ空間時通過F12查看JS文件,找到它的對應演算法。它位於名為qzfl_v8_2.1.57的js文件中。由於該文件內容過大,近6千行,在firebug中直接看response還找不到,不過可以通過在response中搜索得到,或者將單獨在瀏覽器中打開,就可以得到它的全部內容了。找到這個g_tk的計算方法:

不要被這裡的hash誤導,在python裡面hash()是一個內置方法,但在JS中,在此處,它只是個變數名而已。在本爬蟲程序裡面是這樣實現的:

def get_g_tk(): """ make g_tk value""" pskey_start = cookie.find("p_skey=") pskey_end = cookie.find(";", pskey_start) p_skey = cookie[pskey_start+7: pskey_end] h = 5381 for s in p_skey: h += (h << 5) + ord(s) return h & 2147483647

主要是通過位移和並運算,得到一個唯一值。

最後

如第3步中貼出來的代碼後面部分寫的,如果好友的空間不對自己開放,那麼是無法獲取到他的說說的,發送請求後有返回,但主要內容是空的。

如果cookie過期了,程序會記錄日誌並自動退出。我的程序運行了15個小時,請求了494個好友的說說文件,發送1萬1千多個請求(每個請求得到一個文件,我的結果文件夾中就有這麼多個文件),cookie沒有過期,也沒有被空間反爬。哦,對了,為了防止反爬蟲,本程序是使用每請求一個文件就暫停5秒的方式應對的。(所以才那麼慢,也不敢上多線程)

最終獲取到的所有好友的說說文件,還需要自己去提取所需要的信息。本程序只獲取源數據,不處理數據。

---------------------------------------------------------------------------------------------------------------------------

2017.3.13 更新

後期已經增加了處理數據的代碼,在下面的Github中,這個代碼的文件名為get_moods_detail.py。它會從獲取到的動態文件(包括文件夾)把QQ號、發表時間、手機型號(如果有)、定位信息(如果有)、配圖和視頻鏈接(如果有)等提取出來保存到名為moods.sqlite的sqlite資料庫中。這個程序需要單獨執行

同時在以下Github中有一個文件夾名為get_single_report,其功能是提取單個用戶的動態信息並使用Echarts作出年、月、星期的圖例。運行它需要先安裝Flask,啟動伺服器後,在地址欄輸入localhost:5000/?qqnum=QQ號碼,即可得到這個QQ號碼的報告

---------------------------------------------------------------------------------------------------------------------------

Github代碼鏈接:QQzone_crawler


推薦閱讀:

左手用R右手Python系列17——CSS表達式與網頁解析
現在的網路爬蟲的研究成果和存在的問題有哪些?

TAG:网页爬虫 | QQ空间 | Python |