puppeteer介紹(一)爬蟲,效能,注入

鬼不語發表於2019-02-28

Puppeteer 谷歌開發是一個 Node 庫,它提供了一個高階 API 來通過 DevTools 協議控制 Chromium 或 Chrome。Puppeteer 預設以 headless 模式執行,但是可以通過修改配置檔案執行“有頭”模式。

能做啥?

  • 生成頁面 PDF,截圖。
  • 抓取單頁應用執行並渲染
  • 自動提交表單,進行 UI 測試,鍵盤輸入等。
  • 建立一個時時更新的自動化測試環境。
  • 用來幫助分析效能問題。

介紹

Puppeteer API 是分層次的,反映了瀏覽器結構

puppeteer介紹(一)爬蟲,效能,注入

這張圖需要了解一下,即是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介紹(一)爬蟲,效能,注入

請求攔截

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/");
複製程式碼

注入

  1. addScriptTag:注入一個指定src(url)或者程式碼(content)的 script 標籤到當前頁面。
  2. 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);
複製程式碼

puppeteer介紹(一)爬蟲,效能,注入

相關文章