原地址:https://github.com/atonasting/zhihuspider
作者: https://www.zhihu.com/people/aton
網站「看知乎」後臺爬蟲的源碼,使用node.js編寫。
環境配置
- 搞一臺服務器,什麼linux都行,我用的是CentOS 6.5;
- 裝個mysql數據庫,5.5或5.6均可,圖省事可以直接用lnmp或lamp來裝,回頭還能直接在瀏覽器看日誌;
- 先安個node.js環境,我用的是0.12.7,更靠後的版本沒試過;
- 執行npm -g install forever,安裝forever好讓爬蟲在後臺跑;
- 把所有代碼整到本地(整=git clone);
- 在項目目錄下執行npm install安裝依賴庫;
- 在項目目錄下創建json和avatar兩個空文件夾;
- 建立一個空mysql數據庫和一個有完整權限的用戶,先後執行代碼裏的setup.sql和startusers.sql,創建數據庫結構並導入初始種子用戶;
- 編輯config.js,標明(必須)的配置項必須填寫或修改,其餘項可以暫時不改:
exports.jsonPath = "./json/";//生成json文件的路徑 exports.avatarPath = "./avatar/";//保存頭像文件的路徑 exports.dbconfig = { host: 'localhost',//數據庫服務器(必須) user: 'dbuser',//數據庫用戶名(必須) password: 'dbpassword',//數據庫密碼(必須) database: 'dbname',//數據庫名(必須) port: 3306,//數據庫服務器端口 poolSize: 20, acquireTimeout: 30000 }; exports.urlpre = "http://www.zhihu.com/";//知乎網址 exports.urlzhuanlanpre = "http://zhuanlan.zhihu.com/";//知乎專欄網址 exports.WPurl = "www.xxx.com";//要發佈文章的wordpress網站地址 exports.WPusername = "publishuser";//發佈文章的用戶名 exports.WPpassword = "publishpassword";//發佈文章用戶的密碼 exports.WPurlavatarpre = "http://www.xxx.com/avatar/";//發佈文章中替代原始頭像的url地址 exports.mailservice = "QQ";//郵件通知服務類型,也可以用Gmail,前提是你訪問得了Gmail(必須) exports.mailuser = "[email protected]";//郵箱用戶名(必須) exports.mailpass = "qqpassword";//郵箱密碼(必須) exports.mailfrom = "[email protected]";//發送郵件地址(必須,一般與用戶名所屬郵箱一致) exports.mailto = "[email protected]";//接收通知郵件地址(必須)
保存,然後進入下一步。
爬蟲用戶
爬蟲的原理其實就是模擬一個真正的知乎用戶在網站上點來點去並收集數據,所以我們需要有一個真正的知乎用戶。
爲了測試可以用你自己的賬號,但從長遠着想,還是專門註冊個小號吧,一個就夠,目前的爬蟲也只支持一個。
我們的模擬過程不必像真的用戶那樣從首頁登錄,而是直接借用cookie值:
註冊激活登錄之後,進入自己的主頁,使用任何有開發者模式或查看cookie插件的瀏覽器,打開知乎中自己的cookie。
可能有很複雜的一大串,但我們只需要其中一部分,即「z_c0」。
複製你自己cookie中的z_c0部分,連等號、引號、分號都不要落下,最後格式大致是這樣的:
z_c0=”LA8kJIJFdDSOA883wkUGJIRE8jVNKSOQfB9430=|1420113988|a6ea18bc1b23ea469e3b5fb2e33c2828439cb”;
在mysql數據庫的cookies表中插入一行記錄,其中各字段值分別爲:
- email:爬蟲用戶的登錄郵箱
- password:爬蟲用戶的密碼
- name:爬蟲用戶名
- hash:爬蟲用戶的hash(每個用戶不可修改的唯一標識,其實這裏用不到,可以暫時留空)
- cookie:剛纔你複製的cookie
然後就可以正式開始運行了。
如果cookie失效或用戶被封,直接修改這行記錄的cookie字段即可。
運行
推薦用forever來執行,這樣不僅方便後臺運行和記錄日誌,還能在崩潰後自動重啓。
示例:
forever -l /var/www/log.txt index.js
其中-l後的地址就是記錄日誌的地方,如果放在web服務器目錄下,就能在瀏覽器裏通過http://www.xxx.com/log.txt 來直接查看日誌了。
在index.js後面加參數(用空格分隔)可以執行不同的爬蟲指令:
- -i 立即執行,如果不加此參數則默認在下一個指定時間執行,如每天凌晨0:05分;
- -ng 跳過抓取新用戶階段,即getnewuser;
- -ns 跳過快照階段,即usersnapshot;
- -nf 跳過生成數據文件階段,即saveviewfile;
- -db 顯示調試日誌。
各階段的功能在下一節介紹。
爲了方便運行,可以將這行命令寫成sh腳本,例如:
#!/bin/bash
cd /usr/zhihuspider
rm -f /var/www/log.txt
forever -l /var/www/log.txt start index.js $*
具體路徑請替換成自己的。
這樣就能通過./zhihuspider.sh 加參數來開啓爬蟲了:
比如./zhihuspider.sh -i -ng -nf就是立即開始任務、跳過新用戶和保存文件階段。
停止爬蟲的方法是forever stopall(或stop序號)。
原理概述
看知乎爬蟲的入口文件是index.js。它通過循環方式在每天指定時間執行爬蟲任務。
每天順序執行的任務有三個,分別是:
- getnewuser.js:通過當前庫內用戶關注者列表的對比,抓取新用戶信息,依靠此機制可以自動將知乎上值得關注的新人納入庫中;
- usersnapshot.js:循環抓取當前庫內用戶資料和答案列表,並以每日快照形式保存下來。
- saveviewfile.js:根據最近一次快照內容,生成用戶分析列表,並篩選出昨日、近日和歷史精華答案發布到「看知乎」網站。
在以上三個任務執行完畢後,主線程會每隔幾分鐘刷新一次知乎首頁,驗證當前cookie是否仍然有效,如果失效(跳到未登錄頁),則會給指定郵箱發送通知郵件,提醒及時更換cookie。
更換cookie的方法和初始化時一致,只需手工登錄一次然後取出cookie值就行了。
如果對具體代碼實現感興趣可以仔細看裏面的註釋,調整一些配置,甚至嘗試自己重構整個爬蟲。
Tips
- getnewuser的原理是通過對比前後兩天快照中用戶的關注數量進行指定抓取,所以必須有了至少兩次快照之後才能開始,之前就算執行也會自動跳過。
- 快照抓到一半是可以恢復的。如果程序出錯崩潰,用forever stop停止它,然後加上參數-i -ng,立即執行並跳過新用戶階段就能從剛纔抓到一半的快照繼續下去了。
- 不要輕易增加快照抓取時的(僞)線程數,即usersnapshots中的maxthreadcount屬性。線程太多會導致429錯誤,同時抓取回來的大量數據可能會來不及寫入數據庫造成內存溢出。所以,除非你的數據庫搭在SSD上,線程不要超過10個。
- saveviewfile生成分析結果的工作需要至少近7天的快照才能進行,如果快照內容少於7天會報錯並跳過。此前的分析工作可以手動查詢數據庫進行。
- 考慮到大多數人並不需要複製一個「看知乎」,已經將自動發佈wordpress文章函數入口註釋掉了。如果你搭建好了wordpress,記得開啓xmlrpc,然後設置一個專門用於發佈文章的用戶,在config.js中配置相應參數並將saveviewfile中的相關代碼解除註釋。
- 由於知乎對頭像做了防盜鏈處理,我們在抓取用戶信息時一併也將頭像獲取了下來,保存在本地,發佈文章時使用的是本地頭像地址。需要在http服務器中將url路徑指向保存頭像的文件夾,或者將保存頭像的文件夾直接放到網站目錄下。
- 代碼可能不太容易讀懂。除了node.js的回調結構本身就較混亂之外,還有一部分原因是最初寫程序時我剛剛開始接觸node.js,有很多不熟悉的地方導致結構混亂沒有來得及改正;另一部分是在多次縫縫補補中累加了許多醜陋的判斷條件和重試規則,如果全部去掉,代碼量可能會下降三分之二。但這是沒有辦法的事,爲了保障一個系統的穩定運行,必須加入這些。
- 本爬蟲源碼基於WTFPL協議,不對修改和發佈做任何限制。
- 蘇莉安很懶,不會及時解答問題和更新版本,作爲開發者應該儘量自己解決。