去年咱們作過一個叫「學長問答」的社羣活動,裏面沉澱了大量有價值的互動信息,後來由於各類緣由終止了。今天和塗騰聊起來,以爲這些信息就這麼沉寂了太浪費。因此就試着用python爬取了知識星球的內容。node
這個過程又學習了一些新的知識,已經在代碼中以批註的形式寫出。但還有一個沒有解決的問題,就是一個提問底下能夠跟好幾個評論,我暫時還不能在輸出結果裏將「一個提問+n個評論」以總體的形式給出,而只能把評論的信息以一個字典的形式展示,這算是沒有爬取的太完全。未來再看看有沒有新的解決方法。python
import requests import json import urllib import csv #頭信息。網站只提供掃碼登錄的方式,沒有帳號密碼。我覺得應該比較麻煩,但在header信息裏找到了Authorization信息以後,直接能夠保持登錄狀態了。 # 令一個標誌是直接在瀏覽器裏訪問內頁網址的話,瀏覽器的報錯是「{"succeeded":false,"code":401,"info":"","resp_data":{}}」,這個很像原來node.js的數據中心沒有登錄的報錯,而數據中心的模擬登錄也是經過在header中添加Authorization來實現的。 headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36', 'Referer': 'https://wx.zsxq.com/dweb/', 'Authorization': '51EC09CA-6BCC-8847-4419-FA04A2FC9E00' } #打開並寫入csv文件 f = open('/Users/damo/Desktop/wendatuan.csv', 'w+') writer = csv.writer(f) writer.writerow(['created_time','ask_name','ask_content','comment']) #定義爬取信息的函數主體 def get_info(url): res = requests.get(url,headers = headers) json_data = json.loads(res.text) datas = json_data['resp_data']['topics'] for data in datas: if 'talk' in data.keys(): # 判斷json中是否包含 talk 這個鍵 ask_name = data['talk']['owner']['name'] ask_content = data['talk']['text'] else: ask_name = '' ask_content = '' if 'show_comments' in data.keys(): comment = data['show_comments'] else: comment = '' created_time = data['create_time'] writer.writerow([created_time,ask_name,ask_content,comment]) # 截止到前面的代碼,已經能夠實現一個頁面的爬取。下面的代碼內容主要任務是實現「如何自動實現多頁面爬取」 # 多頁面的爬取是經過Network中Query String Parameters來實現的:這裏提供兩個參數,觀察以後發現count是固定值,而end_time和網址最後的時間是同樣的。 # 只不過在網頁中用到了 urlencode的轉化,這部分是新學習的知識。 # 在這個爬蟲案例中,網頁構造的核心邏輯是「上一組最後一個數據的建立時間恰好是下一組數據訪問網址中的一個參數」,以此來構造循環抓取的網址 end_time = datas[19]['create_time'] url_encode = urllib.parse.quote(end_time) # urlencode,將網址中的文本轉化 next_url = 'https://api.zsxq.com/v1.10/groups/518282858584/topics?count=20&end_time='+url_encode # 經過觀察構造下一組數據的網址 get_info(next_url) # 這裏比較巧,直接在函數內部再次調用函數,從而實現不斷的自循環 if __name__ == '__main__': url = 'https://api.zsxq.com/v1.10/groups/518282858584/topics?count=20' get_info(url)