目錄
1. 前言
我是一個真正的知乎小白。
上班的時候,自己手頭的事情處理完了,我除了在掘金摸魚,就是在知乎逛貼。在我的認知中,知乎是一個高質量論壇,基本上各種“疑難雜症”都能在上面找到相應的專業性回答。但平時逗留在知乎的時間過多,我不知道自己是被知乎上面的精彩故事所吸引,還是爲知乎上面的高深技術而着迷。
咱是理科生,不太懂過於高深的哲學,自然不會深層次地剖析自己,只能用數據來說話。於是,就有了這篇博客。
相關的項目源碼放在我的github
2. 博客結構圖
博客的結構圖如上所示。這篇博客主要講述兩件事:爬取知乎用戶數據和對用戶數據進行分析。這個結構圖基本能夠概述分析知乎用戶信息的思路,具體的思路詳述和技術實現細節可看博客後面的內容。
3. 爬取知乎用戶數據
3.1 知乎用戶頁面解析
我的知乎主頁信息預覽如下:
從該頁面的內容來看,我當前需要爬取的知乎信息就在兩個紅框中。然後每個知乎用戶主頁對應的URL路徑應該不一樣,這裏URL中標識是我的主頁就是mi-zhi-saber
,這個URL標識就是知乎裏面的url_token
。也就是說拿到足夠多的url_token
,就可以自己組裝URL來獲取用戶的信息。
通過分析知乎頁面結構,我們可以按照如下思路來爬取用戶信息:
- 基於用戶的個人主頁信息,爬取、解析並保存用戶信息。
上面用戶主頁鏈接對應的頁面內容如下:
對比這兩個頁面,可以推斷出裏面部分字段的意義(其實字段名稱已經足夠見名知意了)。綜合考慮後,我要爬取的字段及其意義如下
字段 | 含義 |
---|---|
url_token |
知乎的用戶標識 |
name |
暱稱 |
gender |
性別(1:男,0:女,-1:未填) |
follower_count |
關注者人數 |
answer_count |
回答數 |
articles_count |
文章數 |
business.name |
所處行業 |
locations.name |
居住地 |
employments.company.name |
公司名稱 |
educations.school.name |
畢業院校 |
educations.major.name |
所學專業 |
- 基於用戶關注的知乎用戶信息,爬取、解析並保存用戶信息。
我關注的知乎用戶信息頁面內容如下:
3. 基於關注用戶的知乎用戶信息,爬取、解析並保存用戶信息。
理論上,選取一個知乎大V作爲根節點,迭代爬取關注者和被關注者的信息,可以拿到絕大部分的知乎用戶信息。
3.2 選取爬蟲框架
要想對知乎用戶進行畫像,必須拿到足夠多的知乎用戶數據。簡單來說,就是說要用java爬蟲爬取足夠多的知乎用戶數據。
工欲善其事,必先利其器。常見的Java爬蟲框架有很多如:webmagic
,crawler4j
,SeimiCrawler
,jsoup
等等。這裏選用的是SpringBoot + SeimiCrawler
,這個方式可以幾乎零配置地使用爬蟲爬取知乎用戶數據。具體如何使用可見於SeimiCrawler官方文檔,或者參考我的源碼。
3.3 使用反反爬手段
論壇是靠內容存活的。如果有另外一個盜版論壇大量地爬取知乎內容,然後拷貝到自己的論壇上,知乎肯定會流失大量用戶。不用想就知道,知乎肯定是採取了一些反爬手段的。
最常見的反爬手段就是User Agent識別
和IP限流
。簡單解釋一下,就是知乎會基於用戶訪問記錄日誌,分析哪個用戶(IP)用哪個瀏覽器(UA)訪問知乎網站的,如果某個用戶極其頻繁地訪問知乎網站,知乎就會把該用戶標記爲“疑似爬蟲的機器人”,然後讓該用戶進行登錄驗證或直接將該用戶對應的IP地址進行封禁。
然後,所謂的“反反爬手段”,就是應對上面所說的反爬手段的。我採取的“反反爬手段”是:
- 收集一些常用的UA,然後每次調用接口訪問知乎網站的時候會刷新所使用的UA。
- 自己在項目中維護一個可高用的免費代理池,每次調用接口訪問知乎網站的時候會使用高可用代理池的隨機一個代理。
實際實踐過程中,提供了免費代理的網站有:西刺代理、89免費代理、雲代理等等,但實際能夠使用的還是隻有西刺代理。
而且西刺代理的可用數也非常少,導致代理池中可用代理數很少,使用代理池的效果不是很好,這真的是一件很沮喪的事。
免費代理池的架構及其實現思路圖:
簡述一下思路:
- 啓動項目時,會自動去爬取西刺代理網站前10頁的代理(共1000個代理),並將其保存到RabbitMQ中。RabbitMQ設置有10個消費者,每個消費者會檢測代理是否可用,檢測完畢後會將該代理的信息及其檢測結果保存到DB中。
- 系統設置了一個定時任務,會定時將DB中當前的所有代理再次放到RabbitMQ中,會由10個消費者檢測代理是否可用,並將檢測結果同時更新到DB中。如果連續3次測試代理不可用,則將該代理從DB中刪除。
- 系統設置了一個定時任務,會定時爬取西刺代理網首頁的所有代理,會檢測代理的可用性,並將其信息及檢測結果再次保存到DB中。這樣保證DB中會定時獲取更多的代理(實際原因是西刺代理可用代理太少,如果不定時獲取更多代理,DB中很快就沒有可用的代理了)。
- 系統設置了一個定時任務,會自動刪除redis中所有的代理。然後再將DB中的代理按檢測成功次數進行排序,將連續成功次數最多的前10個代理保存進redis中。這樣redis中的代理就是高可用的。
3.4 調用接口爬取數據
項目一定程度地屏蔽了代理池以及知乎用戶數據解析的實現複習性,以暴露接口的方式提供爬取知乎用戶信息的功能。
在配置好Redis/RabbitMQ環境後,成功啓動項目,等項目穩定後(需要等到redis中有高可用的代理,否則就是用本機IP直接進行數據爬取,這樣的話本機IP很容易會被封)後,即可通過調用如下接口的方式爬取知乎用戶信息。
- 調用接口
localhost:8980/users
爬取指定知乎用戶的信息,修改url_token
的值即可爬取不同知乎用戶的信息。
- 調用接口
localhost:8980/users/followees
爬取關注指定知乎用戶的用戶信息,修改url_token
的值即可爬取關注不同知乎用戶的用戶信息。
- 調用接口
localhost:8980/users/followers
爬取指定知乎用戶關注的用戶信息,修改url_token
的值即可爬取不同知乎用戶關注的用戶信息。
在實際測試爬取知乎網站用戶信息的過程中,如果系統只用一個固定IP進行爬取數據,基本爬取不到10萬數據該IP就會被封。使用了代理池這種方式後,由於西刺代理網址上可用的免費代理太少了,最終爬取到167萬左右數據後,代理池中基本就沒有可用的IP了。不過爬取到這麼多的數據已經夠用了。
4. 分析知乎用戶數據
4.1 數據去重
爬取了167萬+知乎用戶數據後,需要對原始數據進行簡單的清理,這裏就是去重。每個知乎用戶有唯一的url_token
,由於這裏爬取的是用戶的關注者與被關注者,很容易就會有重複的數據。
數據量有167萬+,使用Java自帶的去重容器Set/Map明顯不合適(內存不夠,就算內存足夠,去重的效率也有待考量)。
項目中實現了一個簡單的布隆算法,能夠保證過濾後的知乎用戶數據絕對沒有重複。
布隆算法的實現思路圖如下:
簡述布隆算法的實現思路如下:
- 首先初始化一個位容器(每個容器單位的值只能是0或1),並先規定好要使用映射數據用的n個
hash
方法,hash
方法的結果對應於該位容器的一個下標。 - 每次存數據之前,需要先判斷該容器中是否已經存過該數據。該數據對應所有
hash
方法的結果,對應在位容器中的下標只要有一個下標對應的單位的值爲0,則表示該容器還沒有存過該數據,否則就判定爲該容器之前存過該數據。 - 每次存數據之後,需要將該數據所有
hash
方法結果對應於位容器中的下標的值,都置爲1。
這裏需要說明一下爲什麼要使用布隆算法以及布隆算法還有什麼缺點。
使用布隆算法的理由:我們是依靠url_token
來判斷一個用戶是否重複的,但url_token
的長度是不確定的,這裏存放一個url_token
所需要的空間按上圖DB中來看基本上有10字節以上。如果使用java容器進行去重,那麼該容器至少需要的空間:10 * 1670000 byte
即大約15.93MB(這裏貌似還是可以使用java容器進行去重,但其實這裏還沒有考慮容器中還需要存的其他信息)。而使用布隆算法,需要的空間:n * 1670000 bit
,使用的hash
方法一般是3-10個左右,即一般至多只需要15.9KB左右的空間(我在項目中使用的是2 << 24 bit
即16KB的容量)。如果數據量繼續增大,布隆算法的優勢會越來越大。
布隆算法的缺點:很明顯地,這種hash
映射存儲的方式肯定會有誤判的情況。即bitSet容器中明明沒有存儲該數據,卻認爲之前已經存儲過該數據。但是隻要hash
方法的個數以及其實現設計得合理,那麼這個誤判率能夠大大降低(筆者水平有限,具體怎麼降低並計算誤判率可自行谷歌或百度)。而且基於大數據分析來說,一定數據的缺失是可以允許的,只要保證過濾後有足夠的不重複的數據進行分析就行。
項目中屏蔽了布隆算法實現的複雜性,直接調用接口localhost:8980/users/filter
,即可將DB中的用戶數據進行去重。
過濾之後,還有160萬左右不重複的數據,說明布隆算法誤判率導致的數據流失,對大量的數據來說影響是可以接受的。
4.2 數據導入ElasticSearch
mysql是一個用來持久化數據的工具,直接用來進行數據分析明顯效果不太好(而且數據量較大時,查詢效率極低),這裏就需要使用更加合適的工具—ElasticSearch。簡單學習一下ElasticSearch,可以參考elasticsearch官網或者我之前寫的一篇博客—SpringBoot整合elasticsearch。
配置好ElasticSearch環境,然後修改配置文件中ElasticSearch相關的配置。調用接口localhost:8980/users/transfer
,即可將DB中的用戶數據遷移到ES中。
SpringBoot整合ElasticSearch非常簡單,直接在項目中導入ElasticSearch的自動配置依賴包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
然後讓相應的DAO層繼承ElasticsearchRepository
即可在項目中使用ElasticSearch。具體如何在springboot項目中使用ElasticSearch,可以參考SpringBoot-ElasticSearch官方文檔,也可參考我項目中源碼。
數據導入ES後,可以在head插件或者kibana插件中查看ES中的數據(head插件或kibana插件可以看去重之後導入ES中的數據有1597696
條)。
4.3 kibana分析知乎數據
我們已經拿到足夠多的用戶數據了,現在需要利用kibana插件來分析數據。我們在Management > Kibana > Index Patterns
中將創建關聯的索引user
後,即可使用kibana插件輔助我們來分析數據。
下面舉幾個例子來表示如何使用Kibana來分析大數據。
- 查詢關注數在100萬及以上的用戶
# 查詢關注數在100萬及以上的用戶
GET user/userInfo/_search
{
"query": {
"range" : {
"followerCount" : {
"gte": 1000000
}
}
}
}
查詢結果圖如下:
簡單地解釋一下結果集中部分字段的意義。took
是指本次查詢的耗時,單位是毫秒。hits.total
表示的是符合條件的結果條數。hits._score
表示的是與查詢條件的相關度得分情況,默認降序排序。
- 聚合查詢知乎用戶的性別比
# 查詢知乎用戶男女性別比
GET /user/userInfo/_search
{
"size": 0,
"aggs": {
"messages": {
"terms": {
"field": "gender"
}
}
}
}
查詢結果圖如下:
直接看數據可能不太直觀,我們還可以直接通過kibana插件不畫相應的結果圖(-1:未填,1:男, 0:女):
從結果圖來看,目前知乎的男女比還不算離譜,比例接近3:2
(這裏讓我有點兒懷疑自己爬取的數據有問題)。
- 聚合查詢人口最集中的前10個城市
# 查詢現居地最多的前10個城市
GET /user/userInfo/_search
{
"size": 0,
"aggs": {
"messages": {
"terms": {
"field": "home",
"size": 10
}
}
}
}
查詢結果圖如下:
從這裏的查詢結果,很容易就可以看出,“深圳”和“深圳市”、“廣州”和“廣州市”其實各自指的都是同一地方。但是當前ES不能智能地識別並歸類(ps: 可能有方法可以歸類但筆者不會…)。因此這裏需要後續手動地將類似信息進行處理歸類。
- 模糊搜索
全字段匹配,“模糊”搜索含有“知乎”的數據,搜索結果圖如下:
4.4 echarts作圖
從上面的kibana畫圖效果來看,真的一般般。這裏更推薦使用kibana收集數據,利用百度開源的數據可視化工具echarts來作圖。
最終的數據彙總以及echarts繪圖效果圖如下:
- 關注數層級統計
很明顯地,絕大部分知乎用戶都是“知乎小白”或者“知乎路人”。這裏的“知乎超大V(1000000+)”的用戶只有3個:“丁香醫生”、“知乎日報”、“張佳瑋”。
- 行業信息統計
手動整理後的行業信息圖如下:
很明顯地能夠看出,大部分知乎用戶所處的行業都與計算機或者互聯網相關。
- 公司信息統計
統計了出現頻率最多的前15名所屬公司統計圖如下:
可以看到,“騰訊”、“阿里”的員工數量遙遙領先。雖然“百度”還是排名第三,但已經不在一個數量級。(“BAT”的時代真的一去不復返了嗎?)
- 職位信息統計
基於職位信息統計圖,利用中文在線詞雲生成器優詞雲,生成出現頻率最多的前100名的職位詞雲圖:
可以看出,除了學生以外,很多知乎用戶都從事計算機或者軟件編程相關的工作,也就是說,知乎用戶中“程序猿/媛”所佔的比重極其的大。
- 大學信息統計
統計了出現頻率最多的前20名畢業院校統計圖如下:
可以看到,填寫了畢業院校的知乎用戶(其實還有絕大部分人沒有完善該信息),這些畢業院校的實力和名氣那是槓槓的。
- 專業信息統計
統計了出現頻率最多的前20名專業統計圖如下:
可以看到,“計算機科學與技術”和“軟件工程”這兩個專業的人數遙遙領先。
- 居住城市信息統計
統計了出現頻率最多的前20名居住城市統計圖如下:
很明顯地,“帝都”和“魔都”的人數遙遙領先。(這裏可以做一個相關性不大、準確度不高的推論:杭州將是下一個“新一線城市”最有力的競爭者。)
5. 總結
從最終的信息統計結果來看,大部分的知乎用戶信息不算完善(信息比例)。但這些統計結果圖,都是基於知乎用戶已經完善的信息進行整理並分析的。很明顯地可以看出,已完善信息的知乎用戶,基本都在發達城市大公司任職,而且其中的很大一部分是“程序猿/媛”。
也就是說,如果我(碼農一枚)在工作中遇到什麼專業難題時,在知乎中尋求到的答案是專業可信的。