使用Puppeteer登入網站抓取資料的Node.js範例碼

最近製作給小孩的相簿,要從學校相簿抓資料,使用puppeteer操作headless 瀏覽器。

1. 進行基本的帳號登入

2. 抓取特定元素

3. 生成簡單json格式


範例碼分為兩個檔案

1. index.mjs 放置主邏輯,使用puppeteerClient操作網頁登入與抓取資料

2. puppeteerClient.mjs 放置啟動/關閉puppeteer得函數


事前需要安裝套件

npm install puppeteer

我這裡使用node 18.20.2,puppeteer是22.7.1版本


解說程式碼

主程式index.mjs

一開始定義數個工具函數

1. waitMs 就是一個等待函數, sleep(mesc)的意思

2. extractUrl 因為從css 屬性的影像url字串會包含起頭與結尾字串,就用它移除

3. getLastPageFromPage 抓最後一頁得頁碼

4. getAlbumsInfosFromPage 抓我需要的相簿資料


主邏輯從使用createClient開始

const client = await createClient({ debug: process.env.DEBUG });

這裡從環境變數讀取是否要設定為除錯模式,會讓headless瀏覽器顯示它的界面,方便除錯與確認問題。


再先定義登入頁面網址,和登入後會跳轉得頁面

const LOGIN_URL = '.../login.html';

const LOGINED_URL = '.../main.html';


最先連到登入頁面並等待完成

await page.goto(LOGIN_URL);

如果已經被跳轉到已登入頁面,就不做登入


進行登入確認loginBtn有出現,因為有動畫所以再稍等一下

  await page.waitForSelector('#loginBtn', { timeout: 5000 });

  await waitMs(2000);


輸入帳號密碼並按下登入

  await page.type('input#account', user, { delay: 180 });

  await page.type('input#password', pass, { delay: 180 });

  await page.click('#loginBtn', { delay: 1000 });

  await page.waitForNavigation();


從網頁抓取所需資料

  const lastPage = await getLastPageFromPage(page) || 1;

  console.log('last page', lastPage);

  const infos = await getAlbumsInfosFromPage(page);

  console.log(JSON.stringify(infos, null, 2));


這裡針對getLastPageFromPage再解釋一下

我這裡用Puppeteer提供的evaluate功能,你可以理解成在瀏覽器的console中執行一些javascript運算,然後將運算結果回傳回我們的node.js執行環境

await page.evaluate(() => {

        const urls = Array.from(document.querySelectorAll('.pagination a[href]'))

        if (urls.length) {

            const lastUrl = urls.pop().href;

            return lastUrl.match(/\d+/g).map(Number)[0];

        }

        return 1;

    });

要注意的是,如果你不能在evaluate中使用定義在Node.js中的函數,會導致錯誤。

透過querySelectorAll去選出頁面中html標籤的class名稱有pagination底下有a元素帶href屬性這些元素,也就是網頁上有一整排分頁的按鈕,我把他們選出來。

然後從取出最後一個元素(.pop)得href內容,再把url中吻合數字的擷取出來,每個都轉換成數值,最後出第一個來。這是因為網頁中分頁url的數值參數只有一個,也就是頁數,所以可以這樣取用我需要的頁數。較完整的作法是丟給URL parser再解出params。

留言