爬蟲 Node.js

前端爬蟲 Puppeteer 介紹

Aimer 2024/02/05 11:14:27
443

前言

最近在研究前端爬蟲,剛好看到 Puppeteer,就想著分享給大家,於是有了這篇。

爬蟲(web crawler/web scraping)

爬蟲主要的目標是自動地做些什麼事情,包含資料搜集、測試、執行任務…等等,藉此提高工作效率。

網路爬蟲的主要優勢和需求主要體現在以下幾個方面:

  • 自動化測試 (automated testing)
    • 模擬使用者操作、提交表單等
    • 可以為應用程式開發、軟體測試和網站管理等提供重要的支援
    • 減少人力成本,建立工作模式 (SOP)。
  • 資料收集 (data collecting)
    • 縮短了手動收集和處理資訊的時間,提升了工作效率
    • 可以對資訊進行解析,並且有結構性的儲存,便於後續的使用或分析
  • 自動化執行任務 (automated tasks)
    • 包含以上內容。

在使用過程中也需要注意尊重網站擁有者的權益,遵守機器人排除協定(Robots Exclusion Protocol)和各種相關法規,避免對被爬取的網站造成不必要的負擔或侵犯。

爬蟲套件的比較差異

常見的網頁爬蟲套件這三個套件(Puppeteer、Cheerio 和 Selenium)在前端爬蟲中扮演不同的角色,各自有其優缺點和特點。

Puppeteer

  • 優點:
    • 提供了完整的瀏覽器控制能力,可模擬使用者的操作瀏覽器行為,支援 JavaScript、HTML、CSS 的渲染和交互。
    • 可以用來進行網頁自動化能力,包括頁面導航、表單填寫、截圖、PDF 生成等工作。
    • 具有豐富的 API 可以直接操作網頁上的元素和事件。
    • Puppeteer 是一個由 Google 開發的 Node.js 庫,專門用於Chrome 瀏覽器的控制和操作。
    • Puppeteer 使用真實的瀏覽器進行操作,因此能夠處理 JavaScript 渲染的頁面,適用於單頁應用程序(SPA)和動態網站的爬取。
    • 可以模擬用戶交互,使其在網站上執行各種操作,如點擊、滾動等。
  • 缺點:
    • 需要較多的系統資源,因為它啟動了一個完整的瀏覽器進程用於模擬了完整的瀏覽器,。
    • 相對於其他輕量級的爬蟲工具,Puppeteer 比較慢且耗時。
    • 如果只是需要解析靜態網頁內容,可能顯得過於龐大。
    • 需要更多的學習成本,因為它使用了一套複雜的 API。

Cheerio

  • 優點:
    • 非常輕量級,適用於解析靜態 HTML 內容。
    • 語法簡單易懂,使用 jQuery 風格的 API,方便選擇、操作和提取 DOM 元素。
    • 適合處理大量數據,效率較高。
    • Cheerio 是一個基於 Node.js 的 HTML 解析庫,用於解析和操作 HTML 文檔。它非常適靜態網頁的爬取,尤其是當你只需要從頁面中提取數據而不需要進行交互時。
    • 輕量級且簡單易用,適合快速開發小型爬蟲。
  • 缺點:
    • Cheerio 只能處理靜態內容,無法執行 JavaScript,因此無法處理需要 JavaScript 動態生成的內容。
    • 不支援瀏覽器渲染,無法模擬瀏覽器行為。
    • Cheerio 無法處理 JavaScript 渲染的頁面,因此對於 SPA 和動態網站可能不太適用。
    • 不能模擬用戶交互,無法執行類似點擊和提交表單的操作。

Selenium

  • 優點:
    • 跨平台性強,支援多種瀏覽器(Chrome、Firefox 等)。
    • 可以模擬人工操作,支援 JavaScript 执行。
    • 可以用多種語言進行控制,如 Python、Java、JavaScript 等。
    • Selenium 是一個跨瀏覽器的自動化測試工具,可以模擬用戶在瀏覽器中的操作。它支持多種編程語言,並且可以用於爬取需要用戶交互的網站。
    • 能夠處理 JavaScript 渲染的頁面,適用於 SPA 和動態網站。
  • 缺點:
    • 相較於 Puppeteer,Selenium 在性能和速度上可能稍微較慢。
    • 安裝和配置有一定複雜度,需要下載驅動器以及設定環境變數等。
    • Selenium 需要下載和配置瀏覽器驅動程序,而且通常比其他兩種庫更慢,因為它模擬了真實的瀏覽器行為。
    • 對於簡單的靜態網頁爬取任務,Selenium 可能會顯得過於複雜。

總結:

  • 如果你需要模擬完整的瀏覽器行為且操作較多互動性的內容,Puppeteer 和 Selenium 可能更適合你。
  • 如果你只需要簡單地解析靜態 HTML 頁面,Cheerio 是一個輕量級的選擇。
  • 每個套件都有其獨特的優勢和限制,根據你的具體需求選擇合適的工具。

套件比較

Puppeteer 介紹

Puppeteer 是由 Google 開發的 Node.js 函式庫,提供方便的 API 來進行網頁測試、屏幕截圖和網頁爬蟲等應用,但僅限於使用 Chromium 瀏覽器引擎的瀏覽器,例如:Google Chrome 或 Microsoft Edge。

  • Chromium 瀏覽器 !== Chrome 瀏覽器
    • Chromium是一個由 Google 主導的開源瀏覽器項目,它提供了一個開放的、可自由使用的瀏覽器引擎,供開發人員使用。
    • Chromium 雖然和 Chrome 九成像,但它其實是 Chrome, Edge 的基礎版本。
    • Chromium 提供了 Chrome 的基本架構和核心功能,而 Chrome 在這個基礎上增加功能,成為一個提供給使用者的完整產品。
    • Chromium 就像是汽車引擎,而 Chrome 就像是整台汽車
  • Puppeteer 的許多用途包括:
    • 產生頁面的截圖和 PDF
    • 爬取 SPA(單一頁面應用程式)並產生預渲染內容(即 "SSR"(伺服器端渲染))
    • UI 自動化測試,模擬表單提交,鍵盤輸入,點擊等行為
    • 建立一個最新的自動化測試環境。
      • 使用最新的 JavaScript 和最新的 Chrome 瀏覽器執行測試案例
    • 捕獲網站的 timeline trace(時間軸跟踪),用來幫助分析效能問題
    • 測試 Chrome 擴充功能

Puppeteer 預設是以 headless(無頭)模式運行。headless 模式是指在爬蟲過程中不顯示瀏覽器視窗畫面,雖然看不到畫面但仍然會執行畫面的渲染過程,也就是說 HTML 的解析、CSS 的套用和 JavaScript 都會正常執行,這樣才能確保畫面內容是正確且完整的。

因為無頭模式少了顯示結果的處理不會做屏幕繪製,所以相較於有頭模式,更能節省資源;但是在開發上有頭模式會方便許多,因為瀏覽器會將渲染好的頁面展示出來,包含了:

  • 處理用戶的交互
  • 應用動畫效果
  • 重新繪製頁面元素
  • 任何有關圖像輸出至瀏覽器的過程…等

無論在無頭模式或有頭模式下,一定要做關閉瀏覽器的動作,無頭模式雖然看不到瀏覽器畫面,實際上背景仍然會有一個瀏覽器真的在跑。所以如果爬蟲完沒有確實地關閉瀏覽器,那麼整個程式就仍然還在運行中,需要手動 Ctrl + C 停止執行。在寫腳本的時候,一定要記得在結束或是發生錯誤的地方把瀏覽器關閉,才能好好地釋放資源

如果希望變更為一般模式,可以藉由設定選項變更為有頭模式,如下:

// 一般模式(有頭模式)
const browser = await puppeteer.launch({
  headless: false,
});

// 無頭模式(Puputeer 預設模式)
const browser = await puppeteer.launch({
  headless: 'new',
});

// 關閉瀏覽器
browser.Close()

Puppeteer 安裝

puppeteer

Puppeteer 會下载最新版本的Chromium(~170MB Mac,~282MB Linux,~280MB Win),以保證可以使用 API。

# 使用 npm
npm i puppeteer
# 使用 yarn
yarn add puppeteer

puppeteer-core

# 使用npm
npm i puppeteer-core
# 使用yarn
yarn add puppeteer-core

自 1.7.0 版本以来,官方維護團隊都會發布一個 puppeteer-core 函式庫,是一個的輕量級的 Puppeteer 版本,用於啟動現有瀏覽器安裝或連接到遠程安裝。

Puppeteer 程式碼語法

起手式

const puppeteer = require("puppeteer");

(async () => {
  // 啟動瀏覽器並開啟一個新的空白頁面
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  // 將頁面導航至 URL
  await page.goto("https://developer.chrome.com/");

	// 關閉
  await page.close();
  await browser.close();
})();

常用語法

const puppeteer = require("puppeteer");

(async () => {
  // 啟動瀏覽器並開啟一個新的空白頁面
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: { width: 1400, height: 900 },
  });
  const page = await browser.newPage();

  // 前往指定 URL
  await page.goto("https://developer.chrome.com/");

  // 設定瀏覽器尺寸
  await page.setViewport({ width: 1080, height: 1024 });

  // 在欄位,輸入文字 "js-text"
  await page.type(".devsite-search-field", "js-text");
  // 操控鍵盤 "Enter"
  await page.keyboard.press("Enter");

  // 等待元素,出現在頁面中
  const searchResultSelector = "a.gs-title";
  await page.waitForSelector(searchResultSelector);

  // 點擊元素
  await page.click(searchResultSelector);

  const textSelector = await page.waitForSelector(".devsite-page-title");
  // 在瀏覽器執行 JavaScript,取得元素資訊
  const fullTitle = await textSelector?.evaluate((el) => el.textContent);

  // 取得頁面尺寸資訊
  const dimensions = await page.evaluate(() => {
    return {
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight,
      deviceScaleFactor: window.devicePixelRatio,
    };
  });

  // 列印結果
  console.log('The title of this blog post is "%s".', fullTitle);
  console.log("Dimensions:", dimensions);

  // 畫面截圖
  await page.screenshot({ path: "example.png" });

  await page.goBack(); // 回到上一頁
  await page.goForward(); // 前往下一頁
  await page.reload(); // 重新整理
  await page.close();
  await browser.close();
})();

參考文獻

 

Aimer