去年我們做過一個叫「學長問答」的社群活動,裡面沉澱了大量有價值的互動資訊,後來因為各種原因終止了。今天和塗騰聊起來,覺得這些資訊就這麼沉寂了太浪費。所以就試著用python爬取了知識星球的內容。
這個過程又學習了一些新的知識,已經在程式碼中以批註的形式寫出。但還有一個沒有解決的問題,就是一個提問底下可以跟好幾個評論,我暫時還不能在輸出結果裡將「一個提問+n個評論」以整體的形式給出,而只能把評論的資訊以一個字典的形式展現,這算是沒有爬取的太徹底。將來再看看有沒有新的解決方法。
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)