Python筆記 · 一個多線程知乎用戶爬蟲的實現

最近用Python編寫了一個獲取知乎用戶主頁信息的多線程爬蟲。

項目地址:github.com/moranzcw/Zhi

首先曬一下成果:

爬蟲運行一天,大約獲取了2.5GB的純文本數據,約72萬知乎用戶主頁的信息。稍後可能會嘗試用Python做一些數據分析和可視化。

程序文件結構

程序文件結構如下:

  • spider文件夾:爬蟲程序文件
    • proxy.py: 包含getproxy()函數,用於獲取代理伺服器的IP地址和埠,調用一次返回一個代理IP。
    • crawl.py: 包含Crawl類,實現用戶頁面的獲取和用戶json信息的提取。
    • datafile.py: 包含DataFile類,實現數據文件的管理和存取。
    • run.py: 程序執行的主要流程,實現了多線程爬蟲,其中一個Master線程管理已爬取列表和生成待爬取任務,並響應Worker線程返回的信息;若干Worker線程,數量可設置,用於爬取用戶信息並存入數據文件中,同時向Master線程返回一個狀態信息。
  • datafile文件夾:存儲數據文件

程序流程

程序流程如下:

這個爬蟲的策略是,選擇一個用戶作為起始點,獲取他的關注列表,加入到任務隊列中,作為之後將要爬取的用戶,繼續獲取這些用戶的關注列表,去重再加入任務隊列,如此循環。把知乎的用戶關係看作一個圖的話,這個策略類似於廣度優先搜索。

至於為什麼使用關注列表而不是被關注列表,因為通常每個用戶關注的用戶都是有效用戶,而被關注列表中往往存在三零用戶,腳本註冊的偽用戶等,這類用戶通常不被其他用戶關注。所以這種策略能高效地篩選出知乎的有效用戶。

代理

知乎擁有一定的反爬蟲機制。在此案例中,知乎的用戶頁面不需要登錄就能查看,所以需要解決的問題就是IP封鎖。筆者簡單測試,對於一個IP,每秒一次請求,大約5分鐘後就會要求輸入驗證碼,可以說非常嚴格,所以使用IP代理服務來解決IP封鎖的問題。

一般來說,我們有兩種解決方案,一種是自己搜集免費代理,建立一個IP代理池,第二種是直接使用付費代理服務。無論哪種,我們的獲取代理IP並爬取目標網站的流程大致是這樣:

通過IP代理服務請求一個IP,再使用這個IP代理伺服器轉發請求,獲取頁面。

筆者使用的IP代理服務略有區別,是一種IP代理隧道,流程大致是這樣的:

對於爬蟲來說,就省略了一個獲取IP的步驟,只需要直接將請求發送到指定的IP代理服務就可以了。

如果需要使用使用上一種通用的IP代理模式,那麼只需要再proxy.py中重寫getproxies函數就可以了。

用戶信息獲取

通常一個請求/響應不能載入一個完整頁面,所以需要一組請求/響應來完成html文本,JavaScript代碼,圖片/音頻等資源文件的載入。不過這個爬蟲案例中,我們在第一次請求/響應中獲取的html文檔就包含我們需要的所有信息。

以用戶vczh為例,其主頁為 zhihu.com/people/excite ,這個頁面下還有anwsers,asks,posts等標籤頁,我們直接訪問following(關注列表)標籤頁,即 zhihu.com/people/excite , 這樣一次請求/響應即可同時獲得用戶信息和用戶關注列表。

打開chrome調試工具,查看第一次請求/響應的詳細內容:

得到html文本後,在html接近末尾的一個div標籤中,有一個data-state屬性,它用json存儲了信息,我們需要的用戶信息和用戶關注列表都在其中:

數據存儲

數據採用csv文件存儲,對於pandas等數據分析工具,csv格式非常方便。

由於程序使用了多線程,所以程序在存取數據時保證了線程安全。

運行爬蟲一段時間後,將會在項目目錄下的datafile文件夾中找到存儲數據的csv文件。

每個csv文件100MB,以方便數據分析,同時降低文件意外損壞帶來的損失。

數據格式為典型的表格:

第一行為表頭,表格一共三列:

1. 第一列為用戶的url token,即用戶主頁url中的id,如用戶vczh的主頁鏈接:zhihu.com/people/excite ,那麼vczh的token就是excited-vczh,這個token具有唯一性。

2. 第二列為對應用戶的數據,數據是json格式的,因為知乎在頁面中是以json來傳送用戶信息的,所以就直接存儲了這個json,Python內置json讀寫函數,非常方便數據分析。

以下是整理格式後,用戶vczh的數據:

{n "isFollowed":false,n "educations":[n {n "major":{n "url":"http://www.zhihu.com/api/v4/topics/19590324",n "avatarUrl":"https://pic1.zhimg.com/e82bab09c_is.jpg",n "name":"軟體學院",n "introduction":"",n "type":"topic",n "excerpt":"",n "id":"19590324"n },n "school":{n "url":"http://www.zhihu.com/api/v4/topics/19599737",n "avatarUrl":"https://pic2.zhimg.com/4d0d193a9_is.jpg",n "name":"華南理工大學(SCUT)",n "introduction":"華南理工大學(South China University of Technology)(原華南工學院,1952年建立):教育部直屬的重點大學,涵蓋理、工、管、經、文、法等多學科,先後成為「211工程」和「985工程」院校,被譽為中國「南方工科大學的一面旗幟」,「工程師的搖籃」,「企業家的搖籃」。校園分為兩個校區,北校區位於廣州市天河區五山高校區,南校區位於廣州市番禺區廣州大學城內。學校佔地面積4417畝(其中南校區1677畝)。北校區湖光山色交相輝映,綠樹繁花香飄四季,民族式建築與現代化樓群錯落有致,環境優美清新,文化底蘊深厚,是教育部命名的「文明校園」;南校區是一個環境優美、設施先進、管理完善、制度創新的現代化校園,是莘莘學子求學的理想之地。",n "type":"topic",n "excerpt":"華南理工大學(South China University of Technology)(原華南工學院,1952年建立):教育部直屬的重點大學,涵蓋理、工、管、經、文、法等多學科,先後成為「211工程」和「985工程」院校,被譽為中國「南方工科大學的一面旗幟」,「工程師的搖籃」,「企業家的搖籃」。校園分為兩個校區,北校區位於廣州市天河區五山高校區,南校區位於廣州市番禺區廣州大學城內。學校佔地面積4417畝(其中南校區1677畝)。北校區湖光山色交相輝…",n "id":"19599737"n }n }n ],n "followingCount":2263,n "voteFromCount":0,n "userType":"people",n "showSinaWeibo":false,n "pinsCount":0,n "isFollowing":false,n "markedAnswersText":"編輯推薦",n "isPrivacyProtected":false,n "accountStatus":[nn ],n "isForceRenamed":false,n "id":"0970f947b898ecc0ec035f9126dd4e08",n "favoriteCount":1,n "voteupCount":1388515,n "commercialQuestionCount":0,n "isBlocking":false,n "followingColumnsCount":73,n "headline":"專業造輪子,拉黑搶前排。gaclib.net",n "urlToken":"excited-vczh",n "participatedLiveCount":6,n "followingFavlistsCount":20,n "isAdvertiser":false,n "isBindSina":true,n "favoritedCount":236566,n "isOrg":false,n "followerCount":583782,n "employments":[n {n "company":{n "url":"http://www.zhihu.com/api/v4/topics/19557307",n "avatarUrl":"https://pic3.zhimg.com/v2-d3a9ee5ba3a2fe711087787c6169dcca_is.jpg",n "name":"Microsoft Office",n "introduction":"Microsoft Office 是一套由微軟開發的辦公軟體。",n "type":"topic",n "excerpt":"Microsoft Office 是一套由微軟開發的辦公軟體。",n "id":"19557307"n },n "job":{n "url":"http://www.zhihu.com/api/v4/topics/19578588",n "avatarUrl":"https://pic1.zhimg.com/e82bab09c_is.jpg",n "name":"Developer",n "introduction":"",n "type":"topic",n "excerpt":"",n "id":"19578588"n }n }n ],n "type":"people",n "avatarHue":"",n "avatarUrlTemplate":"https://pic1.zhimg.com/3a6c25ac3864540e80cdef9bc2a73900_{size}.jpg",n "followingTopicCount":34,n "description":"長期開發跨三大PC平台的GUI庫<br><a href="https://link.zhihu.com/?target=http%3A//www.gaclib.net" class=" external" target="_blank" rel="nofollow noreferrer"><span class="invisible">http://www.</span><span class="visible">gaclib.net</span><span class="invisible"></span><i class="icon-external"></i></a>,討論QQ群:231200072(不閑聊)<br>不再更新的技術博客:<a href="https://link.zhihu.com/?target=http%3A//www.cppblog.com/vczh" class=" external" target="_blank" rel="nofollow noreferrer"><span class="invisible">http://www.</span><span class="visible">cppblog.com/vczh</span><span class="invisible"></span><i class="icon-external"></i></a>",n "business":{n "url":"http://www.zhihu.com/api/v4/topics/19619368",n "avatarUrl":"https://pic1.zhimg.com/e82bab09c_is.jpg",n "name":"計算機軟體",n "introduction":"徼",n "type":"topic",n "excerpt":"徼",n "id":"19619368"n },n "avatarUrl":"https://pic1.zhimg.com/3a6c25ac3864540e80cdef9bc2a73900_is.jpg",n "columnsCount":5,n "hostedLiveCount":0,n "isActive":1,n "thankToCount":0,n "mutualFolloweesCount":0,n "markedAnswersCount":4,n "coverUrl":"https://pic1.zhimg.com/v2-67b965aa94a92ed49b1a4205145b5cf4_b.jpg",n "thankFromCount":0,n "voteToCount":0,n "isBlocked":false,n "answerCount":16163,n "allowMessage":false,n "articlesCount":66,n "name":"vczh",n "questionCount":487,n "locations":[n {n "url":"http://www.zhihu.com/api/v4/topics/19583552",n "avatarUrl":"https://pic4.zhimg.com/161f6ece791a4950ded3278fb74a2f9b_is.jpg",n "name":"西雅圖(Seattle)",n "introduction":"西雅圖是美國西北部最大的城市。多家高科技公司的總部(Microsoft, Amazon,Boeing 等等)坐落於此。",n "type":"topic",n "excerpt":"西雅圖是美國西北部最大的城市。多家高科技公司的總部(Microsoft, Amazon,Boeing 等等)坐落於此。",n "id":"19583552"n }n ],n "badge":[nn ],n "url":"http://www.zhihu.com/api/v4/people/0970f947b898ecc0ec035f9126dd4e08",n "messageThreadToken":"4874924000",n "logsCount":2365,n "followingQuestionCount":26892,n "thankedCount":176110,n "gender":1n}n

可以看到,用戶vczh的大部分基本信息都被包含了。

3. 第三列保存每個用戶的關注用戶列表,每個用戶只保存20個,此列不用作為數據,只作為爬蟲中斷後恢復現場和任務隊列地用處。分析數據時可以忽略。

並發

程序使用多線程來解決網路IO阻塞導致CPU空閑的問題。

由於Python原生解釋器的GIL鎖,Python的多線程只是在一個CPU上切換運行,而不是在多個CPU上並行運行,所以使用場景有一些限制。換句話說,對於一顆四核心的CPU,一個Python程序實例最高只有25%的佔用率。

不過對於此爬蟲案例,GIL鎖並不是瓶頸,筆者測試,此程序在使用某個付費代理服務時,在200線程的情況下,能保持100請求/s的並發,CPU佔用率約在17%-22%(筆記本四核i7),帶寬佔用不足1MB/s。

推薦閱讀:

Python從零開始系列連載(26)——Python特色數據類型(函數)(上)
Python數據分析及可視化實例之Pandas函數速查表
Python編程(bbb四):兩個實用的Python的裝飾器
用Python寫個彈球的遊戲
[17] Python循環語句(四)

TAG:编程 | Python | python爬虫 |