Puppeteer 例項程式碼
阿新 • • 發佈:2018-11-25
啟動/關閉瀏覽器、開啟頁面
// 啟動瀏覽器 const browser = await puppeteer.launch({ // 關閉無頭模式,方便我們看到這個無頭瀏覽器執行的過程 // headless: false, timeout: 30000, // 預設超時為30秒,設定為0則表示不設定超時 }); // 開啟空白頁面 const page = await browser.newPage(); // 進行互動 // ... // 關閉瀏覽器 // await browser.close();
設定頁面視窗大小
// 設定瀏覽器視窗
page.setViewport({
width: 1376,
height: 768,
});
輸入網址
// 位址列輸入網頁地址
await page.goto('https://google.com/', {
// 配置項
// waitUntil: 'networkidle', // 等待網路狀態為空閒的時候才繼續執行
});
儲存網頁為圖片
await page.screenshot({ path: 'path/to/saved.png', });
儲存網頁為 pdf
await page.pdf({
path: 'path/to/saved.pdf',
format: 'A4', // 儲存尺寸
});
執行指令碼
要獲取開啟的網頁中的宿主環境,我們可以使用 Page.evaluate 方法:
// 獲取視窗資訊 const dimensions = await page.evaluate(() => { return { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight, deviceScaleFactor: window.devicePixelRatio }; }); console.log('視窗資訊:', dimensions); // 獲取 html // 獲取上下文控制代碼 const htmlHandle = await page.$('html'); // 執行計算 const html = await page.evaluate(body => body.outerHTML, htmlHandle); // 銷燬控制代碼 await htmlHandle.dispose(); console.log('html:', html);
Page.$ 可以理解為我們常用的 document.querySelector, 而 Page.$$ 則對應 document.querySelectorAll。
自動提交表單
// 位址列輸入網頁地址
await page.goto('https://google.com/', {
waitUntil: 'networkidle', // 等待網路狀態為空閒的時候才繼續執行
});
// 聚焦搜尋框
// await page.click('#lst-ib');
await page.focus('#lst-ib');
// 輸入搜尋關鍵字
await page.type('辣子雞', {
delay: 1000, // 控制 keypress 也就是每個字母輸入的間隔
});
// 回車
await page.press('Enter');
抓取單頁應用: 模擬餓了麼外賣下單
關鍵程式碼
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone6 = devices['iPhone 6'];
console.log('啟動瀏覽器');
const browser = await puppeteer.launch();
console.log('開啟頁面');
const page = await browser.newPage();
// 模擬移動端裝置
await page.emulate(iPhone6);
console.log('位址列輸入網頁地址');
await page.goto(url);
console.log('等待頁面準備好');
await page.waitForSelector('.search-wrapper .search');
console.log('點選搜尋框');
await page.tap('.search-wrapper .search');
await page.type('麥當勞', {
delay: 200, // 每個字母之間輸入的間隔
});
console.log('回車開始搜尋');
await page.tap('button');
console.log('等待搜素結果渲染出來');
await page.waitForSelector('[class^="index-container"]');
console.log('找到搜尋到的第一家外賣店!');
await page.tap('[class^="index-container"]');
console.log('等待選單渲染出來');
await page.waitForSelector('[class^="fooddetails-food-panel"]');
console.log('直接選一個菜品吧');
await page.tap('[class^="fooddetails-cart-button"]');
// console.log('===為了看清楚,傲嬌地等兩秒===');
await page.waitFor(2000);
await page.tap('[class^=submit-btn-submitbutton]');
// 關閉瀏覽器
await browser.close();
關鍵步驟是:
- 載入頁面
- 等待需要點選的 DOM 渲染出來後點擊
- 繼續等待下一步需要點選的 DOM 渲染出來再點選
關鍵的幾個指令:
- page.tap(或 page.click) 為點選
- page.waitForSelector 意思是等待指定元素出現在網頁中,如果已經出現了,則立即繼續執行下去, 後面跟的引數為 selector 選擇器,與我們常用的document.querySelector 接收的引數一致
- page.waitFor 後面可以傳入 selector 選擇器、function 函式或 timeout 毫秒時間,如 page.waitFor(2000) 指等待2秒再繼續執行,例子中用這個函式暫停操作主要是為了演示
以上幾個指令都可接受一個 selector 選擇器作為引數,這裡額外介紹幾個方法:
- page.$(selector) 與我們常用的 document.querySelector(selector) 一致,返回的是一個 ElementHandle 元素控制代碼
- page.$$(selector) 與我們常用的 document.querySelectorAll(selector) 一致,返回的是一個數組
在有頭瀏覽器上下文中,我們選擇一個元素的方法是:
const body = document.querySelector('body');
const bodyInnerHTML = body.innerHTML;
console.log('bodyInnerHTML: ', bodyInnerHTML);
而在無頭瀏覽器裡,我們首先需要獲取一個控制代碼,通過控制代碼獲取到環境中的資訊後,銷燬這個控制代碼。
// 獲取 html
// 獲取上下文控制代碼
const bodyHandle = await page.$('body');
// 執行計算
const bodyInnerHTML = await page.evaluate(dom => dom.innerHTML, bodyHandle);
// 銷燬控制代碼
await bodyHandle.dispose();
console.log('bodyInnerHTML:', bodyInnerHTML);
除此之外,還可以使用 page.$eval:
const bodyInnerHTML = await page.$eval('body', dom => dom.innerHTML);
console.log('bodyInnerHTML: ', bodyInnerHTML);
page.evaluate 意為在瀏覽器環境執行指令碼,可傳入第二個引數作為控制代碼,而 page.$eval 則針對選中的一個 DOM 元素執行操作。