採集網頁內容是一項很常見的需求,比較傳統的靜態頁面,curl 就能搞定。但若是頁面中有動態加載的內容,好比有些頁面裏經過 ajax 加載的文章正文內容,又若是有些頁面加載完成後進行了一些額外處理(圖片地址替換等等……)而你想採集這些處理事後的內容。那麼牛逼閃閃的 curl 也一籌莫展了。php
作過相似需求的人可能會說,老鐵,上 PhantomJS 啊!html
沒錯,這是一個辦法,並且在至關長的時間裏 PhantomJS 是爲數很少的能解決這類需求的工具裏的佼佼者。node
但今天這裏要介紹的是一個後來居上的工具 -- puppeteer,它是隨着 Chrome Headless 技術興起而快速發展起來的。並且很是關鍵的是,puppeteer 由 Chrome 的官方團隊開發和維護,能夠說至關靠譜了!git
puppeteer 是一個 js 包,要想在 Laravel 中使用,得藉助於另外一神器spatie/browsershot
。github
安裝 spatie/browsershotajax
browsershot 是一個 composer 包,出自於大神團隊 spatieshell
$ composer require spatie/browsershot
安裝 puppeteernpm
$ npm i puppeteer --save
也能夠全局安全 puppeteer 但就我的經驗而言,在項目中安裝是比較推薦的作法,由於這樣不一樣項目不會同時受全局安裝的 puppeteer 影響,此外項目中安裝也方便使用 phpdeployer 進行升級(phpdeploy 升級時不會影響線上項目運行,要知道升級/安裝 puppeteer 但是很費時的,有時候還不能保證一次成功)。安裝 puppeteer 時會下載 Chromium-Browser,鑑於咱特殊國情,頗有可能出現沒法下載的狀況,對此,就請你們各顯神通吧……瀏覽器
以採集今日頭條手機版頁面文章內容爲例。安全
use Spatie\Browsershot\Browsershot; public function getBodyHtml() { $newsUrl = 'https://m.toutiao.com/i6546884151050502660/'; $html = Browsershot::url($newsUrl) ->windowSize(480, 800) ->userAgent('Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36') ->mobile() ->touch() ->bodyHtml(); \Log::info($html); }
運行後能夠在日誌中看到以下內容(截圖中只是其中部分)
此外,也能夠將頁面保存爲圖片或 PDF 文件。
use Spatie\Browsershot\Browsershot; public function getBodyHtml() { $newsUrl = 'https://m.toutiao.com/i6546884151050502660/'; Browsershot::url($newsUrl) ->windowSize(480, 800) ->userAgent('Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36') ->mobile() ->touch() ->setDelay(1000) ->save(public_path('images/toutiao.jpg')); }
圖片裏那些框與系統字體有關。代碼中使用了一個 setDelay() 方法,是爲了讓內容加載完成後再進行截圖,簡單粗暴,可能不是最好的解決辦法。
puppeteer 被應用於測試、採集等場景,是一個很是有力的工具。對於輕度的採集任務,是夠用的,好比本文這類在 Laravel (php) 裏來用採集一些小頁面,但若是須要快速採集大量內容,仍是 Python 啥的吧。