什么是網絡爬蟲?
網絡爬蟲(又被稱為網頁蜘蛛,網絡機器人,在FOAF社區中間,更經常的稱為網頁追逐者),是一種按照一定的規則,自動地抓取萬維網信息的程序或者腳本。另外一些不常使用的名字還有螞蟻、自動索引、模擬程序或者蠕蟲。
網絡爬蟲會遇到的問題
有人抓取,就會有人想要防御。網絡爬蟲在運行過程中也會遇到反爬蟲策略。常見的有:
- 訪問頻率限制;
- Header頭部信息校驗;
- 采用動態頁面生成;
- 訪問地址限制;
- 登錄限制;
- 驗證碼限制等。
這些只是傳統的反爬蟲手段,隨着AI時代的到來,也會有更先進的手段的到來。
一個簡單的爬蟲示例
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; public class Reptile { public static void main(String[] args) { // 傳入你所要爬取的頁面地址 String url1 = "http://www.xxxx.com.cn/"; // 創建輸入流用於讀取流 InputStream is = null; // 包裝流, 加快讀取速度 BufferedReader br = null; // 用來保存讀取頁面的數據. StringBuffer html = new StringBuffer(); // 創建臨時字符串用於保存每一次讀的一行數據,然后 html 調用 append 方法寫入 temp; String temp = ""; try { // 獲取 URL; URL url2 = new URL(url1); // 打開流,准備開始讀取數據; is = url2.openStream(); // 將流包裝成字符流,調用 br.readLine() 可以提高讀取效率,每次讀取一行; br = new BufferedReader(new InputStreamReader(is)); // 讀取數據, 調用 br.readLine() 方法每次讀取一行數據, 並賦值給 temp, 如果沒數據則值 ==null, // 跳出循環; while ((temp = br.readLine()) != null) { // 將 temp 的值追加給 html, 這里注意的時 String 跟 StringBuffer // 的區別前者不是可變的后者是可變的; html.append(temp); } // 接下來是關閉流, 防止資源的浪費; if (is != null) { is.close(); is = null; } // 通過 Jsoup 解析頁面, 生成一個 document 對象; Document doc = Jsoup.parse(html.toString()); // 通過 class 的名字得到(即 XX), 一個數組對象 Elements 里面有我們想要的數據, 至於這個 div的值,打開瀏覽器按下 F12 就知道了; Elements elements = doc.getElementsByClass("xx"); for (Element element : elements) { // 打印出每一個節點的信息; 選擇性的保留想要的數據, 一般都是獲取個固定的索引; System.out.println(element.text()); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
示例分析:
- 輸入想要爬取的url地址;
- 發送網絡請求獲取頁面內容;
- 使用jsoup解析dom;
- 獲取需要的數據,輸出到控制台。
網路爬蟲框架
設計框架的目的就是將這些流程統一化,將通用的功能進行抽象,減少重復工作。設計網絡爬蟲框架需要哪些組件呢?
- url管理;
- 網頁下載器;
- 爬蟲調度器;
- 網頁解析器;
- 數據處理器。
- URL管理器
爬蟲框架要處理很多的 URL,我們需要設計一個隊列存儲所有要處理的 URL,這種先進先出的數據結構非常符合這個需求。 將所有要下載的 URL 存儲在待處理隊列中,每次下載會取出一個,隊列中就會少一個。我們知道有些 URL 的下載會有反爬蟲策略, 所以針對這些請求需要做一些特殊的設置,進而可以對 URL 進行封裝抽出 Request。
- 頁面下載器
如果沒有網頁下載器,用戶就要編寫網絡請求的處理代碼,這無疑對每個 URL 都是相同的動作。 所以在框架設計中我們直接加入它就好了,至於使用什么庫來進行下載都是可以的,你可以用 httpclient 也可以用 okhttp, 在本文中我們使用一個超輕量級的網絡請求庫 oh-my-request (沒錯,就是在下搞的)。 優秀的框架設計會將這個下載組件置為可替換,提供默認的即可。
- 爬蟲調度器
調度器和我們在開發 web 應用中的控制器是一個類似的概念,它用於在下載器、解析器之間做流轉處理。 解析器可以解析到更多的 URL 發送給調度器,調度器再次的傳輸給下載器,這樣就會讓各個組件有條不紊的進行工作。
- 網頁解析器
我們知道當一個頁面下載完成后就是一段 HTML 的 DOM 字符串表示,但還需要提取出真正需要的數據, 以前的做法是通過 String 的 API 或者正則表達式的方式在 DOM 中搜尋,這樣是很麻煩的,框架 應該提供一種合理、常用、方便的方式來幫助用戶完成提取數據這件事兒。常用的手段是通過 xpath 或者 css 選擇器從 DOM 中進行提取,而且學習這項技能在幾乎所有的爬蟲框架中都是適用的。
- 數據處理
普通的爬蟲程序中是把 網頁解析器 和 數據處理器 合在一起的,解析到數據后馬上處理。 在一個標准化的爬蟲程序中,他們應該是各司其職的,我們先通過解析器將需要的數據解析出來,可能是封裝成對象。 然后傳遞給數據處理器,處理器接收到數據后可能是存儲到數據庫,也可能通過接口發送給老王。
基本特性
上面說了這么多,我們設計的爬蟲框架有以下幾個特性,沒有做到大而全,可以稱得上輕量迷你挺好用。
-
易於定制:很多站點的下載頻率、瀏覽器要求是不同的,爬蟲框架需要提供此處擴展配置
-
多線程下載:當 CPU 核數多的時候多線程下載可以更快完成任務
-
支持 XPath 和 CSS 選擇器解析
架構圖