天天看點

爬蟲技術的門道,這篇文章總結的最全

Web是一個開放的平台,這也奠定了Web從90年代初誕生直至今日将近30年來蓬勃的發展。然而,正所謂成也蕭何敗也蕭何,開放的特型、搜尋引擎以及簡單易學的HTML、CSS技術使得Web成為了網際網路領域裡最為流行和成熟的資訊傳播媒介;但如今作為商業化軟體,Web這個平台上的内容資訊的版權卻毫無保證,因為相比軟體用戶端而言,你的網頁中的内容可以被很低成本、很低的技術門檻實作出的一些抓取程式擷取到,這也就是這一系列文章将要探讨的話題—— 網絡爬蟲 。

有很多人認為Web應當始終遵循開放的精神,呈現在頁面中的資訊應當毫無保留地分享給整個網際網路。然而我認為,在IT行業發展至今天,Web已經不再是當年那個和PDF一争高下的所謂 “超文本”資訊載體 了,它已經是以一種 輕量級用戶端軟體 的意識形态的存在了。而商業軟體發展到今天,Web也不得不面對知識産權保護的問題,試想如果原創的高品質内容得不到保護,抄襲和盜版橫行網絡世界,這其實對Web生态的良性發展是不利的,也很難鼓勵更多的優質原創内容的生産。

未授權的爬蟲抓取程式是危害Web原創内容生态的一大元兇,是以要保護網站的内容,首先就要考慮如何反爬蟲。

從爬蟲的攻防角度來講

最簡單的爬蟲,是幾乎所有服務端、用戶端程式設計語言都支援的http請求,隻要向目标頁面的url發起一個http get請求,即可獲得到浏覽器加載這個頁面時的完整html文檔,這被我們稱之為“同步頁”。

作為防守的一方,服務端可以根據http請求頭中的User-Agent來檢查用戶端是否是一個合法的浏覽器程式,亦或是一個腳本編寫的抓取程式,進而決定是否将真實的頁面資訊内容下發給你。

這當然是最小兒科的防禦手段,爬蟲作為進攻的一方,完全可以僞造User-Agent字段,甚至,隻要你願意,http的get方法裡, request header的 Referrer 、 Cookie 等等所有字段爬蟲都可以輕而易舉的僞造。

此時服務端可以利用浏覽器http頭指紋,根據你聲明的自己的浏覽器廠商和版本(來自 User-Agent ),來鑒别你的http header中的各個字段是否符合該浏覽器的特征,如不符合則作為爬蟲程式對待。這個技術有一個典型的應用,就是 PhantomJS 1.x版本中,由于其底層調用了Qt架構的網絡庫,是以http頭裡有明顯的Qt架構網絡請求的特征,可以被服務端直接識别并攔截。

除此之外,還有一種更加變态的服務端爬蟲檢測機制,就是對所有通路頁面的http請求,在 http response 中種下一個 cookie token ,然後在這個頁面内異步執行的一些ajax接口裡去校驗來訪請求是否含有cookie token,将token回傳回來則表明這是一個合法的浏覽器來訪,否則說明剛剛被下發了那個token的使用者通路了頁面html卻沒有通路html内執行js後調用的ajax請求,很有可能是一個爬蟲程式。

如果你不攜帶token直接通路一個接口,這也就意味着你沒請求過html頁面直接向本應由頁面内ajax通路的接口發起了網絡請求,這也顯然證明了你是一個可疑的爬蟲。知名電商網站amazon就是采用的這種防禦政策。

以上則是基于服務端校驗爬蟲程式,可以玩出的一些套路手段。

基于用戶端js運作時的檢測

現代浏覽器賦予了JavaScript強大的能力,是以我們可以把頁面的所有核心内容都做成js異步請求 ajax 擷取資料後渲染在頁面中的,這顯然提高了爬蟲抓取内容的門檻。依靠這種方式,我們把對抓取與反抓取的對抗戰場從服務端轉移到了用戶端浏覽器中的js運作時,接下來說一說結合用戶端js運作時的爬蟲抓取技術。

剛剛談到的各種服務端校驗,對于普通的python、java語言編寫的http抓取程式而言,具有一定的技術門檻,畢竟一個web應用對于未授權抓取者而言是黑盒的,很多東西需要一點一點去嘗試,而花費大量人力物力開發好的一套抓取程式,web站作為防守一方隻要輕易調整一些政策,攻擊者就需要再次花費同等的時間去修改爬蟲抓取邏輯。

此時就需要使用headless browser了,這是什麼技術呢?其實說白了就是,讓程式可以操作浏覽器去通路網頁,這樣編寫爬蟲的人可以通過調用浏覽器暴露出來給程式調用的api去實作複雜的抓取業務邏輯。

其實近年來這已經不算是什麼新鮮的技術了,從前有基于webkit核心的PhantomJS,基于Firefox浏覽器核心的SlimerJS,甚至基于IE核心的trifleJS,有興趣可以看看這裡和這裡 是兩個headless browser的收集清單。

這些headless browser程式實作的原理其實是把開源的一些浏覽器核心C++代碼加以改造和封裝,實作一個簡易的無GUI界面渲染的browser程式。但這些項目普遍存在的問題是,由于他們的代碼基于fork官方webkit等核心的某一個版本的主幹代碼,是以無法跟進一些最新的css屬性和js文法,并且存在一些相容性的問題,不如真正的release版GUI浏覽器。

這其中最為成熟、使用率最高的應該當屬 PhantonJS 了,對這種爬蟲的識别我之前曾寫過一篇部落格,這裡不再贅述。PhantomJS存在諸多問題,因為是單程序模型,沒有必要的沙箱保護,浏覽器核心的安全性較差。

如今Google Chrome團隊在chrome 59 release版本中開放了headless mode api,并開源了一個基于Node.js調用的headless chromium dirver庫,我也為這個庫貢獻了一個centos環境的部署依賴安裝清單。

headless chrome可謂是headless browser中獨樹一幟的大殺器,由于其自身就是一個chrome浏覽器,是以支援各種新的css渲染特性和js運作時文法。

基于這樣的手段,爬蟲作為進攻的一方可以繞過幾乎所有服務端校驗邏輯,但是這些爬蟲在用戶端的js運作時中依然存在着一些破綻,諸如:

基于plugin對象的檢查

基于language的檢查

基于webgl的檢查

基于浏覽器hairline特性的檢查

基于錯誤img src屬性生成的img對象的檢查

基于以上的一些浏覽器特性的判斷,基本可以通殺市面上大多數 headless browser 程式。在這一點上,實際上是将網頁抓取的門檻提高,要求編寫爬蟲程式的開發者不得不修改浏覽器核心的C++代碼,重新編譯一個浏覽器,并且,以上幾點特征是對浏覽器核心的改動其實并不小。

更進一步,我們還可以基于浏覽器的 UserAgent 字段描述的浏覽器品牌、版本型号資訊,對js運作時、DOM和BOM的各個原生對象的屬性及方法進行檢驗,觀察其特征是否符合該版本的浏覽器所應具備的特征。

這種方式被稱為 浏覽器指紋檢查 技術,依托于大型web站對各型号浏覽器api資訊的收集。而作為編寫爬蟲程式的進攻一方,則可以在 headless browser 運作時裡預注入一些js邏輯,僞造浏覽器的特征。

另外,在研究浏覽器端利用js api進行 robots browser detect 時,我們發現了一個有趣的小技巧,你可以把一個預注入的js函數,僞裝成一個native function,來看看下面代碼:

爬蟲進攻方可能會預注入一些js方法,把原生的一些api外面包裝一層proxy function作為hook,然後再用這個假的js api去覆寫原生api。如果防禦者在對此做檢查判斷時是基于把函數toString之後對[native code]的檢查,那麼就會被繞過。是以需要更嚴格的檢查,因為bind(null)僞造的方法,在toString之後是不帶函數名的。

反爬蟲的銀彈

目前的反抓取、機器人檢查手段,最可靠的還是驗證碼技術。但驗證碼并不意味着一定要強迫使用者輸入一連串字母數字,也有很多基于使用者滑鼠、觸屏(移動端)等行為的行為驗證技術,這其中最為成熟的當屬Google reCAPTCHA。

基于以上諸多對使用者與爬蟲的識别區分技術,網站的防禦方最終要做的是封禁ip位址或是對這個ip的來訪使用者施以高強度的驗證碼政策。這樣一來,進攻方不得不購買ip代理池來抓取網站資訊内容,否則單個ip位址很容易被封導緻無法抓取。抓取與反抓取的門檻被提高到了ip代理池經濟費用的層面。

機器人協定

除此之外,在爬蟲抓取技術領域還有一個“白道”的手段,叫做robots協定。你可以在一個網站的根目錄下通路/robots.txt,比如讓我們一起來看看github的機器人協定,Allow和Disallow聲明了對各個UA爬蟲的抓取授權。

不過,這隻是一個君子協定,雖具有法律效益,但隻能夠限制那些商業搜尋引擎的蜘蛛程式,你無法對那些“野爬愛好者”加以限制。

寫在最後

對網頁内容的抓取與反制,注定是一個魔高一尺道高一丈的貓鼠遊戲,你永遠不可能以某一種技術徹底封死爬蟲程式的路,你能做的隻是提高攻擊者的抓取成本,并對于未授權的抓取行為做到較為精确的獲悉。

這篇文章中提到的對于驗證碼的攻防其實也是一個較為複雜的技術難點,在此留一個懸念,感興趣可以加關注期待後續文章進行詳細闡述。

另外,歡迎對抓取方面感興趣的朋友關注我的一個開源項目webster, 項目以Node.js 結合Chrome headless模式實作了一個高可用性網絡爬蟲抓取架構,借以chrome對頁面的渲染能力, 可以抓取一個頁面中 所有的js及ajax渲染的異步内容;并結合redis實作了一個任務隊列,使得爬蟲程式可以友善的進行橫向、縱向的分布式擴充。

作者:5u9ar

連結:

https://juejin.im/post/5a22af716fb9a045132a825c

繼續閱讀