WebMagic
首先,爬蟲的本質:基于Http協定請求目标位址擷取響應結果解析并存儲。
01
導語
1、爬蟲基礎知識
2、優秀國産開源爬蟲架構webmagic剖析
02
爬蟲基礎
1、爬蟲的本質
爬蟲的本質:基于Http協定請求目标位址擷取響應結果解析并存儲。
2、HTTP請求
- 請求頭(Request Headers):包裝了http請求的基本資訊,比較重要的如:user-agent、referer、cookie、accept-language(接受語言)、請求方法(post、get)。
- 響應頭(Response Headers):包裝了伺服器傳回的頭資訊,如content-language内容語言、content-type内容的類型text/html等 、server伺服器類型(tomcat、jetty、nginx等)、status響應狀态(如:200、302、404等等)。
- Response:服務端具體的傳回,類型多種多樣,有html頁面、js代碼、json串、css樣式、流等等。
3、解析
通常情況下,web傳回的基本都是html頁面、json。
- xpath:xml路徑語言,具備很強的解析能力,chrome、firefox都有對應的工具生成xpath文法,可以很友善的對标準html檔案進行解析。
- jsonpath:jsonpath是一個json解析的利器,非常類似于xpath文法,用非常簡潔的表達式解析json串。
- css選擇器:這裡的css選擇器和jquery有點類似,通過元素的css樣式來定位元素,大名鼎鼎的jsoup提供豐富的css選擇器
- 正規表達式
- 字元串分割
4、難點
- 分析請求
ajax的普及,很多網站都采用了動态渲染的模式,請求不再是簡單的傳回html的模式,那麼給爬取帶來了巨大的難度,一般隻能靠分析異步請求傳回的json來具體分析,解析成我們需要的資料格式。還有一類是通過服務端内部轉發來渲染頁面,這類是最難的,請求不是通過浏覽器來請求,而是再服務端跳轉幾次才渲染給浏覽器,這時候需要使用模拟器來模拟請求,如selenium等。
- 網站的限制
-
- cookie限制:很多網站是要登陸後才能繞過filter才能通路,這時候必須模拟cookie
- user-agent:有的網站為了防爬蟲,必須要求是真正浏覽器才能通路,這時候可以模拟 user-agent
- 請求加密:網站的請求如果加密過,那就看不清請求的本來面目,這時候隻能靠猜測,通常加密會采用簡單的編碼,如:base64、urlEncode等,如果過于複雜,隻能窮盡的去嘗試
- IP限制:有些網站,會對爬蟲ip進行限制,這時候要麼換ip,要麼僞裝ip
- 曲線方案:對應pc端,很多網站做的防護比較全面,有時候可以改一下思路,請求app端服務試試,通常會有意想不到的收獲。
- 爬取深度
網站通常的表現形式是一個頁面超連結着另外的頁面,理論上是無限延伸下去的,這時候必須設定一個爬取深度,不能無窮無盡的爬取。
- 總結
爬蟲本質上隻做了兩件事情:請求和解析結果,但是爬蟲的開發是非常困難的,需要不停的分析網站的請求,不停的跟随目标網站來更新自己的程式,試探解密、破解目标網站限制,把它當做網絡攻防一點也不為過。
03
webmagic 架構解析
webmagic 是一個優秀的國産爬蟲架構、簡單易用、提供多種選擇器,如css選擇器、xpath、正則等等,預留了多個擴充接口,如Pipeline、Scheduler、Downloader等。
上圖複制于webmagic官方文檔,webmagic由四部分組成
- Downloader:負責請求url擷取通路的資料(html頁面、json等)。
- PageProcessor:解析Downloader擷取的資料。
- Pipeline:PageProcessor解析出的資料由Pipeline來進行儲存或者說叫持久化。
- Scheduler:排程器通常負責url去重,或者儲存url隊列,PageProcessor解析出的url可以加入Scheduler隊列,用于下一次的爬取。
Webmagic使用非常簡單,實作PageProcessor 接口,即可利用Spider類啟動爬蟲任務了。
下面重點解析一下Spider類的幾個重要方法,包括鎖的使用
1、addUrl
scheduler.push(request, this),把需要爬取的url加入到Scheduler隊列。
2、initComponent
初始化downloader、pipelines、threadPool線程池,這裡有必要說明一下,webmagic預設down是HttpClientDownloader、預設pipeline是ConsolePipeline.
2、run
run方法是整個爬行運作的核心
- 任務結束時機
隊列為空并且所有正在運作請求完成,且設定了exitWhenComplete為true,這時才會退出任務,這時候必須注意一點是,當頁面請求過于慢,導緻新解析的url來不及進隊列,這時候任務退出導緻爬取不完整。一般設定exitWhenComplete為false,但是有時候開啟兩個爬蟲,必須等上一個爬蟲完成,才運作下一個爬蟲,這時候就會出問題了。實作這種場景,得改一下webmagic源碼
- 等待新請求時間,預設是30s
- 标題
- 若scheduler隊列裡有url,在把任務丢進線程池,頁面download成功,則執行pageProcessor的process方法,如果有pipeline,則執行pipeline鍊裡的process方法
有一點要注意,對于PageProcessor接口和Pipeline接口的實作,特别要注意線程安全的問題,切記不可對單例集合對象塞元素。
- 線程池CountableThreadPool的execute方法
這裡有死鎖的風險,當threadAlive數大于等于threadNum線程數,reentrantLock.lock()申請鎖,循環condition.await(),與此同時 executorService.execute方法中的threadAlive的decrementAndGet也必須reentrantLock.lock()申請鎖,此時,兩方互相等待資源而造成死鎖,這個小bug調整一下,無礙大局。到時候官方提一個issues
總體說來,Webmagic架構清晰,擴充容易,使用友善,是一款不錯的爬蟲架構。