前言
網頁爬蟲 (web crawler) 會自動地存取網站,省下人為操作所需的時間和精力。網頁爬蟲常常用在自動化測試 (automated testing)、資料收集 (data collecting)、自動化執行任務 (automated tasks) 等情境。在本文中,我們不急著寫程式,先對 Puppeteer 和其他的網路爬蟲做一些概念上的介紹。
網頁爬蟲面面觀
根據網路爬蟲存取網站時是否有瀏覽器 (browser) 介入,可將網頁爬蟲分為兩類:
- 網頁客戶端程式 (HTTP client)
- 瀏覽器自動化 (Browser Automation)
這兩類爬蟲各有優缺點,我們會於下文介紹。
網頁客戶端程式
以網頁客戶端程式為基礎的爬蟲不使用瀏覽器,直接透過機器人 (程式) 和網頁伺服器互動。存取網頁後需要自行撰寫程式來處理頁面。
由於不使用瀏覽器,這類爬蟲速度快、記憶體用量少、易於發佈 (deployment)。由於前述優點,很多網頁爬蟲的教材會先教這類型的爬蟲,但其實這類型的爬蟲比較難寫。除了靜態網站比較好處理外,對於表單 (form) 傳送、Ajax 呼叫等,都要自行追蹤程式碼,寫程式去模擬這些動作。
此外,這類爬蟲「上網」的行為會和一般的瀏覽器有差異,要另外撰寫程式處理標頭 (header)、cookie 等客戶端資料,讓爬蟲「看起來」和一般的真人使用者差不多。這些資訊都要開真的瀏覽器,慢慢追蹤網頁的程式碼,才能知道如何撰寫相對應的程式。
如果網頁是用 JavaScript 程式動態生成的,因這類爬蟲沒有瀏覽器,無法執行 JavaScript 程式,故無法爬取這類型網站。這時候,就要用下文介紹的另一類爬蟲。
瀏覽器自動化
相對於前一節所介紹的爬蟲,以瀏覽器自動化為基礎的爬蟲會透過真實的瀏覽器和網頁伺服器互動。
由於有用到瀏覽器,這類爬蟲「上網」的行為和真人較接近,也不需要處理標頭、cookie 等客戶端資料。如果要傳送表單,只要用機器人按表單按鈕即可。即使網頁透過 JavaScript 動態生成頁面,由於爬蟲有用到瀏覽器,也可順利拜訪這些網頁。
那為什麼不全部的爬蟲都用這種方式來寫呢?因為這類爬蟲有用到瀏覽器,故速度慢、記憶體用量大、不易發佈。對於遠端主機來說,我們通常不想安裝瀏覽器這類相對肥大的軟體。
合格的蟲師 (爬蟲程式設計師) 應該要能區分不同網站的特性,根據當時的情境選擇最適當的爬蟲方案。
以瀏覽器自動化為基礎的爬蟲方案有以下數種:
- Selenium
- Puppeteer
- PhantomJS
由於 PhantomJS 已經停止開發了,我們不詳談。接著,我們來介紹一下 Selenium 和 Puppeteer。
Selenium 的好與壞
Selenium 是相當知名的瀏覽器自動化軟體。原本 Selenium 是自動網頁測試軟體,但也可以當成通用的網頁爬蟲軟體。
Selenium (西元 2004 年) 已經發佈 10 多年了,算是相當成熟的軟體。Selenium 本身以 Java 撰寫,有許多語言的 binding。官方的 binding 就有 Java、C#、Python、Ruby、Node.js (JavaScript) 等語言。除此之外,還有一些非官方的社群 binding。
以 Selenium 為基礎的機器人可以操作 Chrome、Firefox、Safari、Internet Explorer 等瀏覽器,泛用性相當好。
雖然 Selenium 相當強大,但 Selenium 依賴於外部真實瀏覽器,而瀏覽器和 Selenium WebDriver 的版本要匹配,發佈起來相對不易。
Puppeteer 的好與壞
相較於成熟穩健的 Selenium,Puppeteer 是新興的網路爬蟲方案。由於 Puppeteer 套件在發佈時,會附帶可匹配的 Chronium。不會像 Selenium 般,有 web driver 和瀏覽器不匹配的問題。
由於 Puppeteer 本身以 NPM 套件發佈,我們可將 Puppeteer 爬蟲程式包在 NPM 套件中,再利用 NPM 套件的特性,快速在異地還原原本的運行環境。比起 Selenium 爬蟲,發佈 Puppeteer 爬蟲程式會比較簡單一些。
此外,Puppeteer 預設即以 headless 模式來執行,在存取網站時不會秀出真正的瀏覽器,爬蟲運行時不會干擾使用者使用電腦。日後要將爬蟲發佈到遠端主機時,headless 模式讓程式發佈更加容易。
但 Puppeteer 不會取代 Selenium,因為 Selenium 可以搭配數種瀏覽器,但 Puppeteer 只能使用 Chronium。此外,Selenium 有數種語言的 binding,但 Puppeteer 爬蟲只能使用 Node.js (JavaScript) 來寫。
有些程式人不喜歡寫 Node.js 程式,包括筆者本身,其中一個原因來自於 Node.js 只能用非同步 I/O 來寫程式。不過,Puppeteer 官網的範例程式刻意使用 async
和 await
等保留字來寫爬蟲,寫起來和其他主流語言相當接近。經過一些練習後,其實不會太難寫。
結語
在本文中,我們介紹了 Puppeteer,並和 Selenium 相互比較,相信各位讀者都對 Puppeteer 有概念了。在後續的文章中,我們會以實際的範例程式,來看 Puppeteer 爬蟲如何撰寫。