當前位置:
首頁 > 最新 > 實戰乾貨:從零快速搭建自己的爬蟲系統

實戰乾貨:從零快速搭建自己的爬蟲系統

更多騰訊海量技術文章,請關注云加社區:https://cloud.tencent.com/developer

作者:張鵬飛

近期由於工作原因,需要一些數據來輔助業務決策,又無法通過外部合作獲取,所以使用到了爬蟲抓取相關的數據後,進行分析統計。在這個過程中,也看到很多同學爬蟲相關的文章,對基礎知識和所用到的技術分析得很到位,只是缺乏快速的實戰系統搭建指導。

本文將簡單歸納網頁爬蟲所需要的基礎知識,著重於實現一套完整可用的小型網頁爬取、分析系統,方便大家在有需要時,能夠快速搭建系統,以用到實踐中去。

關於網頁爬蟲的定義和用途,想必做技術的都有所了解,這裡就不再贅述。目前, 大家使用爬蟲的目的除搜索引擎屬於無差別爬取外,其他多用於垂直領域或特定網站內容的爬取,本文以特定網站內容爬取作為切入點,當然,也可以應用於垂直領域。

一套合格的網頁爬取、分析系統,大致分為:網頁抓取、網頁分析與鏈接發現、任務去重與調度、數據預處理與存儲、防反爬蟲策略、進度展示等幾個重要方面。下邊逐一做簡單歸納介紹。

一、基礎知識

(1)網頁爬取

網頁讀取,即讀取給定網頁的完整內容,包含非同步載入的內容,也就是完整地呈現到瀏覽器窗口的內容。

隨著智能手機的普及,網頁普遍分為 PC 端 和 移動設備端,由於不同端的網速、流量、設備速度、屏幕大小等原因,移動設備端多採用非同步載入的方式來優化用戶體驗,timeline 類型的無縫翻頁就是最佳的例子。這導致常用的 python requests, python urlib, wget, curl 等獲取到的網頁內容不完整,只有網頁的骨架而無內容,內容需要等待 JS 非同步載入。

這種問題的解決,我們一般使用帶 JS 執行引擎的瀏覽器驅動來執行網頁內的非同步載入 JS,解決非同步載入問題。常見的解決方案是 selenium 自動化瀏覽器測試組件配合 chromedriver 或 firfoxdriver 這些有界面瀏覽器來使用,如果是 linux 伺服器命令行下,則可配合 phantomjs 這款無界面瀏覽器。

python selenium 安裝:pip install selenium

phantomjs 下載地址:http://phantomjs.org/download.html

這裡附上簡單的應用示例代碼:

(2)網頁分析與鏈接發現

網頁分析,即將爬取到的網頁內容進行分析,提取需要的內容。鏈接發現,即提取該網頁中需要進一步爬取的 URI 地址,或者利用網頁內信息構建 URI 地址。

網頁分析所針對的內容,大致分為:結構化內容(如 HTML 和 JSON)、半結構化內容(如一條含 JSON 的 JS 語句),非結構化內容(如純 txt)。(嚴格意義上說,結構化內容為固定的類似資料庫二維表一樣的內容,這裡僅針對網頁內容做適當的分類調整)

針對 HTML ,推薦使用 pyquery 進行分析。pyquery 的使用非常簡單,用於爬蟲時也無需用到高級特性,常用方法如下例所示:

from pyquery import PyQuery as pq web = pq( "http://www.qq.com" )

print web("title").text() # 列印標題

print web("span#guess").text() # 列印 WWWQQCOM 標籤區域的文本

print web("span.undis").text() # 列印 騰訊網 標籤區域的文本

print web("a.qqlogo").attr("href") # 列印 騰訊網 的連接內容

針對 JSON,可使用 python 原生的 json 模塊進行分析。

針對半結構化的內容,則需要特定的分析,一般格式固定,如添加定長的前綴和後綴,但此處無法通用,針對性強,比如含有 JSON 內容,只能固定暴力地將其提取出來再分析。

(3)任務去重與調度

主要是防止網頁的重複抓取,比如 A 中包含了 B 的地址,B 中又包含了返回 A 的地址,如果不做去重,則容易造成爬蟲在 A 和 B 間死循環的問題。但同時也要注意去重的時間窗口,無限期的去重將導致網頁內容無法重新爬取被更新。調度是從系統特性的角度出發,網頁爬取的主要耗時是在 網路交互,等待一個網址進行 DNS 解析、請求、返回數據、非同步載入完成等,需要幾秒甚至更長的時間。小批量任務情況下,簡單地使用多線程(thread)、多進程(subprocess)都可以解決問題,python 2.7,也可以使用 twitter 開源的 tornado 框架內的 coroutine 模塊做協程,python 3.4 本身也提供了非同步 async 關鍵字。

(4)數據存儲與預處理、防反爬蟲策略、進度展示

數據預處理,即篩掉無用的內容,並格式化有用數據,降低存儲的壓力和數據大小,也方便後期分析處理。一般網頁抓取時,需要的是展現在用戶面前的文字和圖片信息,而網頁內的 css 樣式表、js 代碼等則不那麼關心,這時,同樣推薦使用 pyquery 進行數據提取,簡直方便好用(不過 pyquery 存在一些小 bug,標籤解析在特定情況下易被 ">" 打斷)。防反爬蟲則可以搜索下"防爬蟲""反爬蟲"等關鍵字,看下實現原理,如果目標網站有,進行針對性破解即可,一般採用隨機 User-Agent 和 降頻等策略都可以繞過,掛代理換 IP 就會麻煩一些,不過大多數瀏覽器驅動也都支持。

(5)數據展示

這是額外的說明,爬取到數據後,進行數據統計分析之後,是要用來輔助決策的,要展示給老闆或產品看的,如何直觀地將成果展示出來呢?這時推薦使用 JS 的 Highcharts 組件進行數據展示。github 上有 Highcharts 的 python 封裝,但使用起來比較麻煩,學習還需要耗費不少時間,這裡封裝了幾個常用圖表形式的簡易 python 介面,如果需要其他類型的圖,按照 highcharts 的文檔進行和已有代碼稍加擴展即可擴充,簡單易用。(代碼整理上傳後貼鏈接)

二、常見爬蟲實現

基礎知識介紹完後,我們來搭建實際的系統。不管是自己動手,還是使用做好的框架或者產品,都需要知道自己的目的是什麼,要達到什麼樣的目的,如果想加深知識學習,那無疑自己動手做一套是最合適的,如果是需要快速完成工作,最好是使用現成的框架或產品。

(1)自己動手

如果想自己開發一個的話,作者也是支持的,簡單開發將基礎組件聯動起來,也可以完成任務,雖然坑比較多,尤其是異常環節處理以及編碼問題的解決。但話說回來,經驗不就是從踩過的坑中學習的嗎?如果想在這方面有所作為,自己寫或仿寫都是必不可少的學習途徑。

由於自己開發的起點層次有很多,最底層的可以從自己建 TCP 鏈接解析 http 協議開始,也可以從利用已有 http 開發庫開始(求別說最底層應該從寫操作系統或協議棧開始。。。)。

常見的使用 python 開發爬蟲的套路:

subrpocess/thread 做多進程任務分發 requests/selenium 網頁抓取 pyquery 網頁分析加鏈接生成 db 或 shelve 做結果存儲 自定義數據統計分析 matlab/highcharts 做報表圖。

其中,網頁獲取可以用 urllib 來替代,pyquery 也可以用 beautifulsoup 或正則來替代,但這兩者都不推薦,用起來比 requests pyquery 麻煩。

db 常用的就是 sqlite,shelve 可以用來存儲 python 對象,如果你的數據分析也是 python 腳本實現,shelve 無疑可以降低不少解析時間。

matlab 做報表圖是畫報表後生成圖片格式。這裡也建議使用 highcharts 來做報表,只是 highcharts 生成的結果是展示成網頁形式,動態渲染。

在常見的報表知會場景中大致分為兩種:1、發定期郵件看走勢;2、網頁展示。如果需要定期郵件,公司內部有提供從 server 發送郵件/rtx 的工具,可以找運維要一下。但是該工具限制無法直接發送圖片,通過將郵件做成 html 格式,將圖片轉為 base64 內嵌進 html 即可。

那麼如何將 highcharts 生成的報表導出圖片呢?新版本的 highcharts 有提供介面,但並不是很好用,因為你的報表也不僅僅是一個圖,多個圖還要手工拼裝,根據郵件客戶端的不同,有可能展示的樣式也會有變化。 這裡我們仍然可以使用 phantomjs 來完成,原理就是使用瀏覽器對渲染後的頁面進行整頁截圖。實現的原理也比較簡單,使用 js 代碼,控制瀏覽器直接以圖片形式渲染網頁,之後保存。由於該需求反響強烈,phantomjs 官網也提供了解決方案:http://phantomjs.org/screen-capture.html,即下載 rasterize.js,按照下面命令來執行截圖。

這個命令的含義是使用 phantomjs 運行 rasterize.js 渲染 my_html.html 並將結果保存到 tmp.png 中。

$ phantomjs rasterize.js ./my_html.html ./tmp.png

生成截圖的過程中有可能遇到的坑,在這裡也提一下,希望後來的同學不會再因為這個問題浪費時間:首先,控制 phantomjs 進行截圖的時候,有可能截圖不完整,這是因為網頁有一個動畫繪製的過程(如 highcharts 圖表頁),可以修改 rasterize.js 內設置的默認 200ms 的超時渲染時間到 5000ms 甚至更長,保證網頁載入完後再截圖。另外,在公司環境下,爬蟲多部署在 server 端的 linux 系統下,伺服器系統很少安裝字體文件,如果截圖出的內容中文字缺失或跟本地預覽樣式不符,一般就是這個問題了。

(2) scrapy

如果到百度或者谷歌上搜 python 爬蟲關鍵字的話,你肯定會看到有不少人推薦使用 scrapy。scrapy 是不錯的爬蟲庫,或者說是爬蟲框架,著重實現了上述的 網頁爬取、任務去重調度功能,也提供網頁內容分析,不過是 xpath 的形式。其他方面,如 結果存儲 和 進度展示 需要開發者自己完成,也沒有提供簡便的頻控防反爬蟲策略的功能。

這個框架歷史悠久,文檔相當的齊全,社區也活躍,不再花大篇幅介紹,使用方面可以看 https://doc.scrapy.org/en/latest/intro/tutorial.html

(3) pyspider

pyspider,是近幾年國人開發的一款爬蟲產品,之所以提升到產品級別,是因為該框架提供了相當完善的爬蟲全流程的功能。從網頁爬取,到內容分析,再到頻控,定時刷新,數據存儲,分散式部署等,做得可圈可點,且相當易用,也是本文重點推薦的系統。

pyspider 簡單的二次開發介面,同時自帶了一個頁面開發調試器。在實際的應用中,配合 phantomjs 進行頁面渲染獲取動態載入數據非常方便。

這裡的我們先看使用方法,體驗一下 pyspider 的強大和易用,再來介紹該框架的架構和實現方法。

github: https://github.com/binux/pyspider/

安裝:

# pip install pyspider

運行:

# pyspider

如果已安裝 phantomjs,則可使用 $ pyspider all 來配合使用。

訪問、開發:

Create project 後,直接點擊 project ,即可進入頁面式的開發調試環境,非常方便。

我們以 douyu 的一個簡單例子來介紹下二次開發代碼的含義

之後點擊右上角 save 後,返回首頁,修改 project status 和 rate/burst 後, 點擊 run 即可執行:

關於 rate/burst,這裡是採用令牌桶做的頻控,這裡設置 0.1/5 的含義是:rate = 0.1 每秒發起 0.1 個請求,即 10s 一個請求,耗費一個令牌;burst = 5,最多並發發起 5 個請求,即耗費 5 個令牌,那麼也意味著並發後,第 6 個請求,要等待 50s。

另外,pyspider 安裝完即可用,默認採用 sqlite 作為資料庫,單機部署,使用本機的 phantomjs 和 xmlrpc。單機性能不足以支撐時,也可以支持各模塊的分散式部署。如果需要分散式部署,就需要了解下 pyspider 的架構情況,和基本的實現原理。

下面來簡要地看一下pyspider 的架構:

從圖中可以看出,pyspider 主要的構成模塊為 調度器 scheduler,網頁爬取 fetcher,數據預處理與鏈接發現 processor,output 到資料庫,還有 web 頁面的進度監控、運營。

結合上述談到的爬蟲幾大塊,淺顯地看一下 pyspider 的實現:

webui 部分,使用 flask 模塊實現。

fetcher 部分使用 tornado 的 gen 模塊內的 coroutine 做協程,當 fetch_type = "js" 的時候則鏈接 phantomjs 進行數據的爬取,否則直接非同步爬取。

processor 處理階段,提供了 pyquery 解析對象 repsonse.doc,也可以直接訪問頁面源碼進行解析,鏈接發現需要用戶自己完成,pyquery 也提供了方便的介面 reponse.doc("a") 即可篩選出所有的 標籤對象。

任務調度,pyspider 採用資料庫來存儲需要的任務,taskid = md5sum( URL ) 為 primary key 保存每個任務鏈接上次執行的時間以及更新時間,以此方式去重和篩選出可執行的任務,放入內部執行隊列中,由 fetcher 提取執行。表結構如下:

數據存儲,也是可配置的,但幾十萬鏈接的小量,還是可以用 sqlite 來存儲。表結構如下:

三、一些遺留的問題及小技巧

1、pyspider 使用 phantomjs 抓取頁面時發現,當請求量較大,會存在 phantomjs 有大量鏈接未關閉,從而停止響應。沒有深入定位具體原因,採用暴力定時重啟 phantomjs 的方式來解決了,有遇到的同學可以深入定位一下。

2、另外,selenium phantomjs 是可以通過執行 js 代碼來操作瀏覽器動作的,所以遇到翻頁自動載入的情況,可以尋找頁內的 more 元素傳送 click() 事件。

3、如果目標網站量較少,不妨試一下手機端的站點,一般手機端站點為了優化用戶體驗,都提供了非同步載入功能,提供非同步載入,則很大可能是使用 ajax 進行 json 明文形式的查詢和結果返回,可以通過 chrome 的 F12 或 safari 的響應式設計模式,記錄請求 timeline,直接定位到網站自身提供的 restAPI 查詢介面,要比解析網頁事半功倍了。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 雲加社區 的精彩文章:

少年,你的告警量可以更少些!

TAG:雲加社區 |