Puppeteer 谷歌開發是一個 Node 庫,它提供了一個高階 API 來通過 DevTools 協議控制 Chromium 或 Chrome。Puppeteer 預設以 headless 模式執行,但是可以通過修改配置檔案執行“有頭”模式。
能做啥?
- 生成頁面 PDF,截圖。
- 抓取單頁應用執行並渲染
- 自動提交表單,進行 UI 測試,鍵盤輸入等。
- 建立一個時時更新的自動化測試環境。
- 用來幫助分析效能問題。
介紹
Puppeteer API 是分層次的,反映了瀏覽器結構
這張圖需要了解一下,即是puppeteer的結構,也是程式碼的順序結構;
// 瀏覽器例項
const puppeteer = require('puppeteer');
// 啟動 返回 browser
const browser = await puppeteer.launch();
// 返回 page
const page = await browser.newPage();
// 跳轉
await page.goto('https://www.baidu.com/');
// 返回page的frame
const frame = await page.mainFrame();
// 當前頁面的url https://www.baidu.com/
console.log(frame.url());
// 關閉
await browser.close();
複製程式碼
- Puppeteer 使用 DevTools 協議 與瀏覽器進行通訊。
- Browser 例項可以擁有瀏覽器。
- BrowserContext 瀏覽器上下文。
- Page 至少有一個框架:主框架。 可能還有其他框架由 iframe 或 框架標籤 建立。
- frame 至少有一個執行上下文 - 預設的執行上下文 - 框架的 JavaScript 被執行。 一個框架可能有額外的與 擴充套件 關聯的執行上下文。
- Worker 具有單一執行上下文,並且便於與 WebWorkers 進行互動。
安裝
// 安裝puppeteer,如果報錯改用 cnpm 安裝
cnpm install puppeteer --save
複製程式碼
常用函式
Puppeteer返回的大部分是Promise支援一下async/await會很方便; 每個功能方法都有很多引數配置,先列舉部分
瀏覽器操作、開啟頁面
上方程式碼內容
跳轉地址
await page.goto('https://google.com/', {
// 配置項 等待網路狀態為空閒的時候才繼續執行
waitUntil: 'networkidle'
});
複製程式碼
生成PDF,截圖
await page.screenshot({ path: "download/example.png" });
await page.pdf({
path: "download/example_pdf.pdf',
format: "A4"
});
複製程式碼
等待
waitFor: 引數可以是<string|number|function> 選擇器, 方法 或者 超時時間
// 等待1s
await page.waitFor(1000);
// 等待元素載入完成
await page.waitForSelector("#id");
複製程式碼
選擇器
- 返回的型別 ElementHandle 表示一個頁內的 DOM 元素;
- 是繼承自 JSHandle。而 JSHandle 表示頁面內的 JavaScript 物件
- 其實是執行的document.querySelector,document.querySelectorAll
// 返回單個,如果多個返回第一個,沒有返回null
const ElementHandle = await page.$("#js_login_select")
// 返回多個,如果沒有返回[]
await page.$$(".js_login_select")
複製程式碼
page.$eval(selector, pageFunction[, ...args])
此方法在頁面內執行 document.querySelector,然後把匹配到的元素作為第一個引數傳給 pageFunction
// 獲取html
const html = await page.$eval("body", e => e.outerHTML);
console.log(html);
// 獲取id
const id = await page.$eval('#div',div => div.id );
//清空輸入框的值,獲取焦點
await page.$eval('#input',input => {
input.focus();
input.value = '';
})
複製程式碼
evaluate
頁面例項上下文中執行的方法
const dimensions = await page.evaluate(param => {
alert("我的方法dimensions和" + param);
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
};
}, "引數");
複製程式碼
eval與evaluate區別
page.evaluate 意為在瀏覽器環境執行指令碼,可傳入第二個引數作為控制程式碼,而 page.$eval 則針對選中的一個 DOM 元素執行操作。
注意:選擇器過濾後得到的dom,都是通過執行querySelector或者querySelectorALl得到的,所以頁面指令碼能執行的方法屬性,都可以在這裡使用
-常用函式
效能分析
Puppetter當然可以分析網站的效能,不過是建立一個可以在Chrome DevTools中開啟的跟蹤檔案。
// 每個瀏覽器一次只能啟用一條跟蹤
await page.tracing.start({
path: "download/trace.json",
screenshots: true
});
// 需要關閉
await page.tracing.stop();
複製程式碼
成功後會在path的位置生成.json的檔案,裡面一堆的數字和變數~ 開啟chrome瀏覽器的devtools,拖進performance中就OK了~
請求攔截
Puppeteer還可以監聽很多事件,load,error,close等等,當然包括request,response
對頁面的圖片請求攔截,如果不是圖片字尾可以找規則篩選
// 啟動 request
await page.setRequestInterception(true);
// 監聽request
page.on("request", interceptedRequest => {
if (
interceptedRequest.url().endsWith(".png") || interceptedRequest.url().endsWith(".jpg") ||
interceptedRequest.url().includes(".jpg")
) {
// 中斷
interceptedRequest.abort();
} else {
interceptedRequest.continue();
}
});
await page.goto("https://www.58pic.com/");
複製程式碼
注入
- addScriptTag:注入一個指定src(url)或者程式碼(content)的 script 標籤到當前頁面。
- addStyleTag:新增一個指定link(url)的 < link rel="stylesheet" > 標籤。 或者新增一個指定程式碼(content)的 < style type="text/css" > 標籤。
await page.addScriptTag({ path: "public/javascripts/test.js" });
await page.addStyleTag({ path: "public/css/test.css" });
複製程式碼
這樣不同站點,只需要注入不同的指令碼爬取
模擬瀏覽器
關於模擬不同的手機,需要不同的引數,Puppeteer準備了很多,可以直接拿來用,在puppeteer/DeviceDescriptors中
const page = await browser.newPage();
// 模擬機型
await page.emulate(iPhone);
複製程式碼