
作者:Masamune
在日常生活中,我們時常會遇到一些采集數據相關的需求,比如獲取一些官方數據整理到excel表中進行統計,聚合一些網頁新聞提高自己的閱讀效率等等。
雖然許多爬蟲教程都是用python寫的,但是我認為Go語言是比python更合適的選擇,Go語言有著優秀的并發特性,很容易就可以寫出高并發量的爬蟲,并且沒有python煩人的編碼轉換混亂的問題。
爬蟲預期的爬取規模決定的爬蟲程序本身的復雜度,本文將從語言到結構部分簡單闡述如何設計一個爬蟲程序。
首先我們選用的Go庫是github.com/PuerkitoBio/goquery,先上示例:
爬取并列出ve2x首頁的文章標題示例
package mainimport ("fmt""github.com/PuerkitoBio/goquery"
)func main() {root, err := goquery.NewDocument("https://www.v2ex.com/")if err != nil {panic(err)}root = goquery.NewDocumentFromNode(root.Find("div#Main").Nodes[0])nodes := root.Find("span.item_title").Nodesfor _, n := range nodes {fmt.Println(goquery.NewDocumentFromNode(goquery.NewDocumentFromNode(n).Find("a").Nodes[0]).Text())}
}
示例結果:
怎么記憶不同發行版的一些差別?
[討論]當代下,對拿來主義和分享主義取舍的迷惑
macOS Mojave 和 Catalina 哪個更好用
誰能做一個監控社會物資捐贈和 redten 字會收入和發放的頁面
macOS 如何更新 Python ?
暫時選擇了 magic keyboard,有沒其他推薦?
git clone 有沒有什么有效的加速方法
誰能提供微軟官網上面的 Win10 鏡像 sha1 值
阿里云輕量級服務器提速原理是啥呢?
為什么我這段返鄉戴笠忽然失效了~~
跨網絡隊列服務項目更新了~ [wukongqueue]
迫于窮, 300 塊錢以內的無線鍵盤、鼠標,求推薦~
有沒有感興趣一起學習英語的?
微信小程序咨詢: 請求私人 API,是否收費問題
- 該庫可以對html文檔結構進行解析,并提供了類似DOM的API對html頁面內的元素的內容進行提取,十分方便,相較于正則表達式來說更加優雅,具體細節可以參照文檔和自己測試。
- 注意調試頁面過程中建議將頁面保存成本地文件,每次運行的時候通過文件讀取頁面,否者抓取頻率過高可能會觸發網站的反爬規則。
- 對于分析頁面的引用庫建議隔離一層接口,方便以后進行替換。
結構設計
對于絕大多數人來說,一個單機單進程的爬蟲已經滿足需求了,但是一個有點規模的爬蟲如何做呢?這里簡答闡述一個分布式的爬蟲的設計思路。
任務分發
這部分建議使用隊列中間件或者隊列云服務,將爬取請求拆分成一個一個任務,投遞到消息隊列,而真實執行爬取任務的程序則從消息隊列里獲取任務進行爬取和分析,再進行數據落地。
任務處理
真實執行爬取任務的程序應該是無狀態的,從隊列獲取到爬取任務后按業務規則進行處理,這部分程序可以通過多節點部署十分方便的進行擴展,不用擔心數據丟失的問題,也方便做并發量的控制。
數據落地
建議通過數據庫進行數據落地,并且針對每個URL的每次請求結果都進行存檔,方便數據回溯,對于存儲空間的消耗可能會相當大,這個需要根據爬蟲規模自行評估如何做數據的落地和輪轉。
數據處理
可以將已經落地的數據接入全文搜索引擎進行處理,具體則根據業務的復雜度和成本選取合適的方案。
URL去重
在爬取任務執行之前,需要判斷URL在之前是否已經爬取過,對于已經爬取過的URL不需要在進行處理。這部分建議使用redis進行處理。對于已經爬取過的URL,作為key存到redis中,每次爬取之前都從redis中嘗試獲取一次,如果存在則跳過,這部分往深了做還可以使用布隆過濾器進行優化,這里不再闡述。
任務再分發
爬蟲任務可能是通過其他程序或者人工生成的,也可能是在爬取任務處理過程中生成的,比如遞歸的爬取某個界面上的超鏈接,在這種情況下需要仔細處理再生成的任務,一些爬蟲陷阱就埋在里面。比如某個連接正常用戶永遠無法點擊到,但是爬蟲在分析html頁面的時候沒有注意而直接進行請求的話,則會觸發反爬規則被屏蔽。
關于反爬蟲
爬取與反爬取是一個永恒的對抗,一般來說,只要爬取頻率不要太高,就不容易觸發網站的反爬規則,思路就是盡量偽裝成正常的客戶端請求。這里有需要注意的幾點:
動態內容處理
有些需要的網頁內容并不是html頁面直接提供的,而是通過瀏覽器渲染后動態生成的,對于這部分頁面,可以交由PhantomJS進行處理,獲得渲染后的頁面再進行分析處理。
UserAgent
一般的HTTP客戶端有一個默認的UserAgent,比如Go語言官方的httpclient的類似:Go-http-client/1.1
,而一般一個普通瀏覽器的UserAgent類似:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
,有些網站可能會通過UserAgent來識別異常的請求來源從而進行限制,當然這種方式比較低級,但確實有效,我們自己在請求的時候可能需要寫入一個比較正常的UserAgent,甚至可以搜集多個常見瀏覽器的UserAgent值,發起請求的時候隨機選取填入。
IP
如果同一個IP存在大量請求,肯定是會進行反爬處理,規避的方案就是需要大量的代理組成代理池,請求的時候隨機選取,通過代理請求則可以避免對單一IP的屏蔽。隨之而來的就是對代理本身請求成功率的評估,如果某一個代理的請求成功率太低,則需要考慮踢出代理池,以免對爬取效率造成影響。
控制爬取頻率
控制爬取頻率是非常重要的,如果請求頻率太高引起網站管理員的注意就得不償失了。這里建議將爬取的請求拆分成一個一個的任務,結合消息隊列進行爬取頻率的控制,可以通過Go本身的channel進行限流,也可以結合外部隊列中間件進行限制。
驗證碼
簡單的方案就是選擇一個識別簡單驗證碼的庫,付費的話可以調用別人的識別驗證碼的API。
爬蟲陷阱
有些超鏈接埋在html頁面里并沒有顯示,正常用戶不可能請求,但是如果爬蟲程序識別為普通超鏈接并且發起請求的話,就會觸發反爬規則被屏蔽。
內容
更惡心的反爬手段是,如果觸發了網站的反爬規則,并不會直接拒絕請求,而是返回看似正常,但其實是虛假的數據。這種問題不易被發現,而且難以追查反爬策略,只能盡可能的關注爬取內容,做好質量控制。
最后
總的來說,爬蟲的規模根據當前需求進行設計,簡單的單機單進程就滿足需求。復雜的就需要考慮設計成分布式程序跨機運行并且具有良好的擴展性。每個人都可以擁有自己的爬蟲,方便自己的生活。