聲明:本文爲原創,轉載請註明出處
本文總共三章,前面兩章廢話吐槽比較多,想看結果的話,直接看第三章(後續會更新,最近忙着畢設呢,畢設也是我自己做的,關於射頻卡的,有時間我也放上來,哈哈)。
- 一,系統總體結構
首先吐槽一下,標題取得好水,原諒我是一枚耿直的工科男。系統框圖如下所示,簡單看一下,對整體有個把握,總體由4個部分組成
上圖中,裝載URL隊列的是先進先出的隊列,整個爬蟲系統的設計就是基於寬度優先遍歷的原則設計的。所以,對於執行整個下載任務的引擎而言,它只是啓動一個線程池,然後機械的從隊列裏面拿出鏈接,下載網頁,然後再將網頁中的鏈接放到隊列裏面,循環上面的操作。由於每一個站點都有其自身佈局的特點,比如特定的編碼,特定的URL格式,面向站點的模板需要提供這些特點,以方便爬取效率和自己想要得到的效果。對於一張網頁,我們真正關心的,講個實話,只是一部分數據,所以在模板獲取數據之前,是先需要對數據進行過濾,排版等相關處理的,面向數據處理的模型就是爲了解決這個問題而產生的。(我去感覺這段話,有種催眠的感覺,發現自己表達能力好差。)
- 二,設計思想及核心流程圖
說點題外話,關於爬蟲的的實現,網上很多,但是隻要你不是我這樣的大老粗,你仔細看就會發現,所有的實現基本都是機械抓取URL,最爲致命的是抓取的URL還有可能是相對URL。那什麼獲取個性化數據就有點大海撈針的感覺了。哈哈,自戀一下,本爬蟲就可以大海撈針(你也可以當笑話看,否則這玩意太枯燥了)。其實我感覺的話,爬蟲的核心無非就兩個:一是要能很好的處理URL,二是方便獲取想要的數據。至於什麼效率,鄙人認爲,在這個計算機處理能力飛速提示的年代,不是那麼重要。
下面是整個引擎執行流程圖:
上圖十分清楚的描述了整個引擎的執行流程圖,現在一看好像很簡單,但是當時寫起來,那個問題,不想說了,不利於弘揚社會主義核心價值觀,哈哈。至於到底是怎麼用我會把代碼放出來(留言qq索取也行,githup還沒有建倉庫呢),有了這個圖大家看起來,也方便些。接下來,實在是不想廢話了,直接看使用demo。
- 三,實踐
正所謂實踐是檢驗真理的唯一標準,這裏以抓取阿里巴巴旗下螞蟻金服的基金數據爲例子,進行簡單講解一下。
3.1 定義一個基於該網站的引擎類。此類需要導入我開發的包,然後繼承自Spider。Spider有幾個函數是用於子類重載的。主要的也就是下面的三個重載子函數.詳情看註釋
public class AliFundtion extends Spider { private WebClient webClient=new WebClient(); private Pattern HREF=Pattern.compile("href=\"(.*?)\""); public AliFundtion(int maxSize,int threadSize){ super(maxSize,threadSize); initWebOptions(); } private void initWebOptions(){ webClient.setAjaxController(new NicelyResynchronizingAjaxController()); webClient.getOptions().setJavaScriptEnabled(true); webClient.getOptions().setCssEnabled(false); webClient.getOptions().setTimeout(35000); webClient.getOptions().setThrowExceptionOnScriptError(false); } /** * 通過重載這個函數,我們這裏只抓取螞蟻金服首頁展示的基金數據,因爲它首頁包含了所有的基金, * 這個函數決定了URL隊列裏面到底有哪些鏈接,是引擎的抓取的來源 * @param html 抓取到的網頁 * @param url 該網頁對應的URL * @param que URL隊列 */ @Override protected void allHrefEnQueue(String html, String url, SpiderQueue que) { if(url.equals("http://www.fund123.cn/fund")){//斷定是首頁 List<String> hrefs=RegexUtil.getAllMatcher(html,1,HREF); for(String href:hrefs){ String absoUrl=Browser.relative2TrUri(href,url);//轉化爲絕對路徑 if(absoUrl.startsWith("http://www.fund123.cn/matiaria?fundCode")){//這正是我們需要的基金數據 que.enQueue(absoUrl); } } } } /** * 這個函數決定了,通過URL獲取網頁的方式,對於需要執行js代碼的網頁而言,重載這個函數是必須得,比如這裏就是基於htmlUnit重載了Spider的這個函數 * @param url 即將抓取的URL * @param charset 所用的字符編碼 * @return 返回抓取到的數據 * @throws IOException */ @Override synchronized protected String toGetHtmlPage(String url, String charset) throws IOException { HtmlPage page=webClient.getPage(url); return page.asXml(); } /** * 注意這裏必須調用父類的close()方法,來釋放一些資源 */ @Override protected void close() { super.close(); webClient.close(); } }
3.2 主程序調用步驟
public class Main { public static void main(String[] args) { //step1: 創建一個你自己定義的爬蟲引擎,第一個參數表示隊列的最大容量,第二個參數表示開啓線程池中線程數量 AliFundtion aliFundtion=new AliFundtion(50,6); //step2:定義你自己的站點模板 ICrawlTemplate temp=new AbstractTemplate() { @Override public void crawlValue(String html, String url) { //todo 在這裏寫下你想做的事,比如將得到的數據持久化到數據庫,或者保存到磁盤,其中html表示被數據模型修飾後的數據,url是該html對應的鏈接 System.out.println(html); } @Override public String getBaseSite() { return "http://www.fund123.cn/fund"; } @Override public String getCharset() { return null; } @Override public boolean filterUrl(String url) { return true; } }; //step3:採用正則表達式進行數據建模 //<_%></_%>這是一對錶示這個一個正則表達式的標籤 //index 屬性 就是該正則表達式需要提取的組 StringBuilder sb=new StringBuilder(); sb.append("基金名稱:").append("<_% index=\"1\">").append("<span class=\"fundmatiaria-title-fundname\">(.*?)</span>").append("</_%>"); sb.append("基金代碼:").append("<_% index=\"1\">").append("<span class=\"fundmatiaria-title-fundcode\">(.*?)</span>").append("</_%>"); sb.append("基金淨值:").append("<_% index=\"1\">").append("<p class=\"fundmatiaria-fundinfo-value\".*?>(.*?)</p>").append("</_%>"); RegexModel model=new RegexModel(sb.toString()); model.getOptions().setAbsoJs(true);//表示將所有js路徑轉化爲絕對路徑 model.getOptions().setAbsoImage(true);//表示將所有image路徑轉化爲絕對路徑 model.getOptions().setAbsoCss(true);//表示將所有css路徑轉化爲絕對路徑 aliFundtion.setModel(model); //step4:下載模板 aliFundtion.downLoadArtcle(temp); } }
3.3 看一下結果:
基金名稱:南方原油(QDII-FOF)
基金代碼:(501018)
基金淨值:1.1502 +1.42% -1.57%
基金名稱:廣發道瓊斯美國石油開發與生產指數(QDII-LOF)A
基金代碼:(162719)
基金淨值:1.1371 +1.65% +0.04%
基金名稱:銀華心誠靈活配置混合
基金代碼:(005543)
基金淨值:0.9507 +1.79% +1.79%