使用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。
留言