java抓取動態生成的網頁--吐槽

最近在作項目的時候有一個需求:從網頁面抓取數據,要求是首先抓取整個網頁的html源碼(後期更新要使用到)。剛開始一看這個簡單,而後就稀里嘩啦的敲起了代碼(在這以前使用過Hadoop平臺的分佈式爬蟲框架Nutch,使用起來是很方便,可是最後由於速度的緣由放棄了,但生成的統計信息在後來的抓取中使用到了),很快holder.html和finance.html頁面成功下載完成,而後解析完holder.html頁面以後再解析finance.html,而後很沮喪的發如今這個頁面中我須要的數據並無在html源碼中,再去瀏覽器查看源碼果真是這樣的,在源碼中確實沒有我須要的數據,看來不是我程序寫錯了,接下來讓人身心疲憊的事情來了---獲取包含動態內容的html頁面。html

  在所謂的中國最強搜索引擎---百度上面行走了好長的時間,發現大部分的人都在將使用WebDriver和HttpUnit(其實前者已經包含了後者),這個高興,終於找到了解決辦法。懷着萬分的激動使用WebDriver,我要想罵人了。java

  下面是關於WebDriver的吐槽web

  WebDriver是一個測試框架,本來設計的時候就不是用來服務爬蟲的,可是我想說的是:八字就差一撇了,你就不能多往前作一步嗎?爲何網上還有那麼多的人推薦WebDriver呢?我想這些人沒有從實際出發,甚至還有的人狂言WebDriver能夠解析完成後的頁面返回給想要爬去整個頁面的人(包含動態生成的內容),對,WebDriver能夠完成這個任務,可是看到做者寫的代碼,我想說的是:哥們,你的代碼侷限性太大了,解析本身寫的js代碼,並且js代碼簡單,這樣WebDriver固然是毫無壓力的完成任務。WebDriver在解析動態內容是要看js代碼的複雜性和多樣性。瀏覽器

  什麼是複雜性?框架

    先貼一段代碼jvm

WebDriver driver = newInternetExplorerDriver ();
HtmlPage page = driver.get(url);
System.out.println(page.asXml());

這一段代碼的意思是相信你們都看懂,上面使用的IE內核,固然還有FirefoxDriver, ChromeDriver,HtmlUnitDriver,這些driver的使用原理都是同樣的,先開啓瀏覽器(這個要時間的),而後加載url並完成動態解析,而後經過page.asXml()就能夠獲得完成的html頁面,其中HtmlUnitDriver模擬無界面瀏覽器,java中有執行js的引擎rhino,HtmlUnitDriver使用的就是rhino來解析js的,因爲不會去啓動有界面的瀏覽器,因此HtmlUnitDriver的速度比前面的三者都快。不管是什麼Driver,避免不了的是解析js,這是須要時間的,並且不用的內核對js的支持程序又是不一樣,好比說HtmlUnitDriver對於帶有滾動的js代碼支持不好,在執行時會報錯(親自體驗了)。js代碼的複雜的意思就是:對於不一樣的內核他們支持的js是不徹底相同的,這個應該根據具體狀況來定,鄙人很久沒有研究js了,因此關於各內核對js的支持就不說了。分佈式

  什麼是多樣性工具

  前面說了,瀏覽器解析js是須要時間的。對於只嵌入少數的js代碼的頁面來講,經過page.asXml()來獲取完整的頁面時沒有問題的。可是對於嵌入比較多的js代碼的頁面,解析js是須要不少時間的(對於jvm來講),那麼此時經過page.asXml()來獲取的頁面中大多數時候是不包含有動態生成的內容的。問題就來了,這樣的話爲何還說WebDriver能夠得到包含有動態內容的html頁面呢?網上有人說在driver.get(url)以後須要是當前線程等待一下才能獲取完成的頁面,也就是相似於下面的形式oop

  

WebDriver driver = new InternetExplorerDriver();
HtmlPage page = dirver.get(url);
Thread.sleep(2000);
System.output.println(page.asXml());

我按照這個想法去嘗試如下,呀,真的是能夠。可是問題不正好也擺在那裏了麼?怎麼樣去肯定等待時間?相似於數據挖掘中肯定閥值時的憑經驗的方法?,仍是儘量的是時間長一點。我以爲這些都不是很好的辦法,時間代價比較大。我就想在driver應該能夠捕獲解析js完成後的狀態,因而我去找啊,找啊,但是根本就沒有這個方法,因此我說WebDriver的設計者爲何再也不往前走一步,讓咱們能夠在程序中獲取到driver解析js完成後的狀態,這樣的話就不用使用Thread.sleep(2000)這樣的不肯定性代碼了,惋惜的是怎麼也找不到,真是讓我心痛了一場。FirefoxDriver, ChromeDriver,HtmlUnitDriver也有一樣的問題,能夠說使用WebDriver來輔助爬去動態生成的網頁所獲得的結果是很不穩定的。這一點我是深有體會,使用IEDriver的時候,同一個頁面兩次爬取的結果會出現不同,並且甚至有時候IE直接掛掉,你說這樣的東西大家敢用在爬蟲程序中嗎?我是不敢的。post

  另外還有就是有人推薦使用HttpUnit,其實WebDirver中HtmlUnitDriver在內部使用的就是httpUnit,因此使用HttpUnit也會遇到一樣的問題,我也作了實驗,確實是這樣。經過Thread.sleep(2000)來等待js的解析完成,我以爲不可取的辦法。不肯定性太大了,特別是在大型的抓取工做中。

  總結一下,WebDriver是爲測試而設計的框架,雖然按照其原理理論上能夠用來輔助爬蟲獲取包含有動態內容的html頁面,可是在實際的應用中是不取的,不肯定性太大了,穩定性太差,速度太慢,咱們仍是讓框架各盡其值吧,不要折煞了他們的優勢。

  個人工做沒有完成,因此繼續去網上需找辦法,此次找到了一個穩定的,肯定性高的輔助工具---phantomjs,目前我還不徹底瞭解這個東西。可是目前已經用它來實現了我想要的功能。在java中經過runtime.exec(arg)來調用phantomjs獲得解析js後的頁面。我仍是把代碼貼出來吧

  phantomjs端要執行的代碼

複製代碼

system = require('system')   
address = system.args[1];//得到命令行第二個參數 接下來會用到   //console.log('Loading a web page');   var page = require('webpage').create();   
var url = address;   
//console.log(url);   page.open(url, function (status) {   
    //Page is loaded!   
    if (status !== 'success') {   
        console.log('Unable to post!');   
    } else {    
    //此處的打印,是將結果一流的形式output到java中,java經過InputStream能夠獲取該輸出內容        console.log(page.content);   
    }      
    phantom.exit();   
});

複製代碼

java端執行的代碼

  

複製代碼

public void getParseredHtml(){
  String url = "www.bai.com";
  Runtime runtime = Runtime.getRuntime();
  runtime.exec("F:/phantomjs/phantomjs/phantomjs.exe F:/js/parser.js "+url);
  InputStream in = runtime.getInputStream();  //後面的代碼省略,獲得了InputStream就好說了     }

複製代碼

這樣的話在java端就能夠得到解析完成後的html頁面了,而不是像WebDriver中須要使用Thread.sleep()這樣的不肯定性的代碼來獲取可能完成的代碼。有一點須要說明:在phantomjs端的js代碼千萬不要要語法錯誤,不然js代碼編譯不一樣的話,java端就一直等待着,並不會拋異常。再就是因爲在使用phantomjs.exe的時候,java端每次都要去開啓一個phantomjs進程,時間上消耗仍是比較大的。可是最起碼來講結果是穩定的。固然最後我尚未使用phantomjs,我直接download須要的數據,並無去抓取整個完整的頁面,主要是速度方面的問題(其實,我不敢用是由於phantomjs不熟悉,因此我慎用)。

  折騰了幾天,雖然沒有解決個人問題,可是見識長了很多,後期的工做是熟悉phantomjs,看能不能再速度方面提高,要是能打破速度的框框,之後再爬去網頁的時候就駕輕就熟了,再者就是Nutch這個框架,我佩服着哥們在使用的時候方便性,全部後期頗有必要研究下如何優化Nutch在Hadoop上的抓取速度,另外,Nutch原始的功能中也不會抓取動態生成的頁面內容,可是可使用Nutch和WebDirver結合,說不定抓取的結果穩定了,哈哈,這些只是構想,可是不嘗試怎麼知道呢?

  若是園友對於使用WebDriver輔助爬蟲所獲得的結果的穩定性方面有要說的,歡迎各位啊,由於我確實沒有找相關的資料來穩定爬去結果。

相關文章
相關標籤/搜索