:::

擷取AJAX動態產生的網頁內容:PhantomJS指令列工具 / Crawling AJAX Webpages with PhantomJS Command Line Utility

image

現在很多網頁內容都是以動態的方式產生,例如Facebook會在開啟網頁之後再來讀取網頁內容,就連「布丁布丁吃什麼?」也是在網頁開啟之後再來慢慢載入旁邊的小工具。這種使用AJAX技巧來調整畫面的網頁,雖然便於一般使用者用瀏覽器查看,但是卻會造成伺服器端用程式抓取網頁的困難。

還好,現在我們可以用Node.js寫成的虛擬瀏覽器PhantomJS來幫我們載入完整的網頁內容。為此我寫了一些搭配PhantomJS使用的命令列腳本,讓我們可以在Linux 32位元環境下以指令端擷取指定網址,並配合jQuery選取器抽取出需要的網頁元素,最後直接回傳顯示在螢幕上。


配置環境 / Environment

phantomjs-logo

PhantomJS有Windows、Mac OS X、Linux 64位元、Linux 32位元、FreeBSD等不同的版本,可以跨平臺運作。不過本篇我是在Linux 32位元 Debian 7的環境下進行開發,所以不適用其他的環境。

要使用PhantomJS,系統還需要安裝一些相關的套件。詳情請看「How to install PhantomJS on Debian/Ubuntu」。

安裝與配置 / Installation

PhantomJS不能獨自運作,必須要搭配Node.js的腳本。而若要搭配jQuery選取器來擷取網頁元素,那又要有jQuery程式檔。因此我寫了一個可以Linux裡面執行的腳本phantomjs.sh,只要搭配網址、jQuery選取器等參數來執行它,這樣就可以將擷取結果輸出到螢幕上啦。

以下說明這個PhantomJS指令列工具怎麼安裝:

先取得Zip壓縮檔,下載到任意的資料夾中,解壓縮它。我先把檔案下載到/tmp為例。配置完成之後的檔案結果如下圖:(請忽略.git資料夾)

2017-03-12_115112

接著我們要把部分檔案加入執行的權限,增加執行權限的指令如下:

#chmod +x phantomjs.sh

指令後面的「phantomjs.sh」就是檔案。要增加執行權限的檔案如下:

  • phantomjs.sh
  • demo.sh
  • lib/phantomjs

好了,這樣PhantomJS指令列工具就配置完成啦。

用法 / Usage

接下來我們來看看要怎麼使用PhantomJS指令列工具。

範例網頁 / Demo AJAX Webpage

這裡有個用AJAX動態產生的網頁範例:http://pulipulichen.github.io/phantomjs/demo/demo.html

image

乍看之下這好像是顯示兩行「After Render!」。

image

但是從原始碼中可以看到,其實原來是兩行「Before Render…」。

如果是使用curl或PHP的file_get_content()等抓取網頁原始碼的工具,那就只能抓到「Before Render…」的內容。如果要抓取讀取完成「After Render!」,那就得用PhantomJS才行!

PhantomJS指令列工具用法 / PhantomJS Command Line Utility Usage

指令如下:

./phantomjs.sh "[URL]" "[SELECTOR]"

[URL]是指要抓取的網頁,例如「http://pulipulichen.github.io/phantomjs/demo/demo.html」。

[SELECTOR]則是jQuery的選取器,例如「div.content」。

若我們以上面的範例網頁為目標,想要抓取裡面含有「content」class屬性的div標籤的內容,那麼指令是這樣的:

./phantomjs.sh "http://pulipulichen.github.io/phantomjs/demo/demo.html" "div.content"

執行結果為:

<div class="content">After Render!</div><div class="content">After Render!</div>

image

這樣就完成抓取網頁的工作了。

這樣的指令列工具可以搭配任何程式語言運作,像是PHP的shell_exec(),很方便吧。


PhantomJS技巧 / Advanced Skill in PhantomJS

PhantomJS號稱下載、解壓縮、執行,就是這麼簡單。但實際上摸索之後,才發現根本就不是這回事。PhantomJS除了用來擷取網頁內容之外,還能夠為運作畫面截圖、執行自動化的腳本(類似Selenium IDE那樣,但不用真的開啟瀏覽器!)等等多種功能,其實非常地複雜。

PhantomJS必須要搭配Node.js腳本才能運作,而這個Node.js又跟一般的Node.js不一樣,是PhantomJS特別編譯的版本,操作方法請見它的API說明

為了解決我想要的「擷取動態產生的網頁內容」跟「以jQuery擷取指定網頁元素」,這篇的Node.js腳本phantomjs-exec.js包含了許多PhantomJS的進階技巧:

除此之外,我也在phantomjs-exec.js裡面加入了快取的功能。第二次執行抓取相同網頁的時候會從快取取得檔案。如果每次都想要開啟最新網頁的話,請修改phantomjs-exec.js的config.enable_cache = false;。

未來如果要做截圖或自動測試的話,應該也會以phantomjs-exec.js這個檔案繼續延伸吧。


小結 / In closing

image

其實這個PhantomJS指令列工具是為了Full Text RSS而寫得。現在許多RSS不僅不提供全文,就連網頁預設顯示的內容也只有摘要,改成讀取完成之後再用AJAX動態產生全文,像是「綠色工廠」或「硬是要學」。或著是許多網頁使用了延遲載入圖片lazyload的功能,導致RSS直接取得的程式碼沒辦法顯示圖片,像是「巴哈姆特GNN新聞」。每次瀏覽RSS的時候都還要跳到網頁才能看到全文,實在是太煩了,所以我就開始研究這篇的PhantomJS。

現在我的Full Text RSS已經內建了PhantomJS。但因為PhantomJS是仰賴系統的服務,所以我沒有直接把它跟Full Text RSS的原始碼擺在一起。取而代之的,我把它做成了OpenVZ虛擬範本,提供有需要的人直接使用吧:

就結果來說,很令我滿意。

雖然PhantomJS使用上比較複雜一些,但只要做好基礎的phantomjs-exec.js,未來各種應用就變得簡單許多。獲得了PhantomJS這個技術,就可以開啟更多可能性,大概就是這種感覺。

不知不覺的,Node.js越寫越多了啊。未來應該也會逐漸轉變成以Node.js為主要的程式語言吧。

0 意見:

留言工具: