木偶簡介

從Node.js以編程方式控制Chrome的簡介

Puppeteer是一個Node庫,我們可以使用它來控制無頭鉻實例。我們基本上是使用Chrome,但是以編程方式使用JavaScript。

使用它,我們可以:

  • 抓取網頁
  • 自動化表單提交
  • 執行任何類型的瀏覽器自動化
  • 跟踪頁面加載效果
  • 創建單頁應用程序的服務器端呈現版本
  • 製作屏幕截圖
  • 創建自動化測試
  • 從網頁生成PDF

它是由Google構建的。它本身並沒有解鎖任何新內容,但是它抽象了許多我們必須處理的細節,而無需使用它們。

簡而言之,它使事情變得非常容易。

由於它在初始化時啟動了一個新的Chrome實例,因此它可能不是性能最高的。不過,這是使用Chrome自動執行測試的最精確方法,因為它使用的是實際的瀏覽器在引擎蓋下。

確切地說,它使用Chromium(Chrome的開源部分),這主要意味著您沒有Google許可的專有編解碼器,並且無法開源(MP3,AAC,H.264 ..),因此您沒有與崩潰報告,Google更新等Google服務集成,但從編程角度來看,它們應該與Chrome 100%類似(媒體播放除外,如前所述)。

安裝木偶

首先使用安裝

npm install puppeteer

在您的項目中。

這將下載並捆綁最新版本的Chromium。

您可以選擇通過安裝來讓puppeteer運行已經安裝的Chrome的本地安裝puppeteer-core相反,這在某些特殊情況下很有用(請參閱木偶vs木偶核心)。通常,你會和puppeteer

使用木偶

在Node.js文件中,要求它:

const puppeteer = require('puppeteer');

然後我們可以使用launch()創建瀏覽器實例的方法:

(async () => {
  const browser = await puppeteer.launch()
})()

我們也可以這樣寫:

puppeteer.launch().then(async browser => {
  //...
})

您可以將帶有選項的對像傳遞給puppeteer.launch()。最常見的是

puppeteer.launch({ headless:false })

在Puppeteer執行操作時顯示Chrome。很高興看到正在發生的事情並進行調試。

我們用await,因此我們必須將此方法調用包裝在異步功能,我們立即調用

接下來,我們可以使用newPage()上的方法browser對象得到page目的:

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
})()

接下來,我們稱goto()上的方法page加載該頁面的對象:

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://website.com')
})()

我們也可以使用promise,而不是async / await,但是使用後者可以使事情更具可讀性:

(() => {
  puppeteer.launch().then(browser => {
    browser.newPage().then(page => {
      page.goto('https://website.com').then(() => {
        //...
      })
    })
  })
})()

獲取頁面內容

在頁面上加載了網址後,我們就可以獲取該頁面了內容稱呼evaluate()的方法page

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://website.com')
<span style="color:#66d9ef">const</span> <span style="color:#a6e22e">result</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">page</span>.<span style="color:#a6e22e">evaluate</span>(() =&gt; {
<span style="color:#75715e">//...

}) })()

該方法具有回調函數,我們可以在其中添加檢索所需頁面元素所需的代碼。我們返回一個新對象,這將是我們的結果evaluate()方法調用。

我們可以使用page.$()訪問方法選擇器API方法querySelector()在文件上,以及page.$()作為別名querySelectorAll()

完成計算後,我們將其稱為close()方法開啟browser

browser.close()

頁面方法

我們在上方看到了page我們從調用中得到的對象browser.newPage(),我們稱goto()evaluate()方法就可以了。

所有方法都返回一個Promise,因此通常在它們前面加上await關鍵詞。

讓我們來看看一些我們將調用的最常見方法。您可以在Puppeteer文檔上查看完整列表

page.$()

允許訪問選擇器API方法querySelector()在頁面上

page.$()

允許訪問選擇器API方法querySelectorAll()在頁面上

page.$eval()

接受2個或更多參數。第一個是選擇器,第二個是函數。如果有更多參數,這些參數將作為附加參數傳遞給函數。

它運行querySelectorAll()在頁面上,使用第一個參數作為選擇器,然後使用該參數作為函數的第一個參數。

const innerTextOfButton = await page.$eval('button#submit', el => el.innerText)

click()

在作為參數傳遞的元素上執行鼠標單擊事件

await page.click('button#submit')

我們可以傳遞帶有選項對象的附加參數:

  • button可以設置為left(默認),right或者middle
  • clickCount是一個默認為1的數字,它設置了應單擊元素的次數
  • delay是兩次點擊之間的毫秒數。默認為0

content()

獲取頁面的HTML源

const source = await page.content()

emulate()

模擬設備。它將用戶代理設置為特定設備,並相應地設置視口。

支持的設備列表可用在這個檔案中

這是模擬iPhone X的方式:

iPhone X

const puppeteer = require('puppeteer');
const device = require('puppeteer/DeviceDescriptors')['iPhone X'];

puppeteer.launch().then(async browser => { const page = await browser.newPage() await page.emulate(device)

//do stuff await browser.close() })

evaluate()

在頁面上下文中評估函數。在此功能內,我們可以訪問document對象,因此我們可以調用任何DOM API:

const puppeteer = require('puppeteer');

(async () => { const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto(https://flaviocopes.com)

const result = await page.evaluate(() => { return document.querySelectorAll(’.footer-tags a’).length })

console.log(result) })()

我們在此處調用的任何內容都是在頁面上下文中執行的,因此如果我們運行console.log(),我們不會在Node.js上下文中看到結果,因為它是在無頭瀏覽器中執行的。

我們可以在此處計算值並返回一個JavaScript對象,但是如果要返回DOM元素並在Node.js上下文中訪問它,則必須使用其他方法,evaluateHandle()。如果我們從Evaluation()返回一個DOM元素,我們將得到一個空對象。

evaluateHandle()

與評價()類似,但是如果返回DOM元素,我們將獲得正確的對象,而不是空的對象:

const puppeteer = require('puppeteer');

(async () => { const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto(https://flaviocopes.com)

const result = await page.evaluateHandle(() => { return document.querySelectorAll(’.footer-tags a’) })

console.log(result) })()

exposeFunction()

此方法使您可以在瀏覽器上下文中添加新功能,該功能在Node.js上下文中執行。

這意味著我們可以添加一個在瀏覽器內部運行Node.js代碼的函數。

本示例在瀏覽器上下文中添加了一個test()函數,該函數從文件系統中讀取“ app.js”文件,並提供相對於腳本的路徑:

const puppeteer = require('puppeteer');
const fs = require('fs');

(async () => { const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto(https://flaviocopes.com)

await page.exposeFunction(‘test’, () => { const loadData = (path) => { try { return fs.readFileSync(path, ‘utf8’) } catch (err) { console.error(err) return false } } return loadData(‘app.js’) })

const result = await page.evaluate(() => { return test() })

console.log(result) })()

focus()

重點介紹作為參數傳遞的選擇器

await page.focus('input#name')

goBack()

返回頁面導航歷史記錄

await page.goBack()

goForward()

在頁面導航歷史中前進

await page.goForward()

goto()

打開一個新頁面。

await page.goto('https://flaviocopes.com')

您可以將帶有選項的對像作為第二個參數傳遞。這waitUntil選項,如果通過了networkidle2值將等待導航完成:

await page.goto('https://flaviocopes.com', {waitUntil: 'networkidle2'})

hover()

將鼠標懸停在作為參數傳遞的選擇器上

await page.hover('input#name')

pdf()

從頁面生成PDF。你可以

await page.pdf({ path: 'file.pdf })

您可以將許多選項傳遞給此方法,以設置生成的PDF詳細信息。查看官方文檔

reload()

重新載入頁面

await page.reload()

screenshot()

拍攝頁面的PNG截圖,並將其保存到使用選定的文件名中path

await page.screenshot({path: 'screenshot.png'})

查看所有選項

select()

選擇由作為參數傳遞的選擇器標識的DOM元素

await page.select('input#name')

setContent()

您可以設置頁面的內容,而不是打開現有的網頁。

有助於以編程方式使用現有HTML生成PDF或屏幕截圖:

const html = '<h1>Hello!</h1>'
await page.setContent(html)
await page.pdf({path: 'hello.pdf'})
await page.screenshot({path: 'screenshot.png'})

setViewPort()

默認情況下,視口為800x600px。如果您想使用其他視口(可能需要截圖),請致電setViewport與傳遞對象widthheight特性。

await page.setViewport({ width: 1280, height: 800 })

title()

獲取頁面標題

await page.title()

type()

輸入標識表單元素的選擇器

await page.type('input#name', 'Flavio')

delay選項允許像真實世界的用戶一樣模擬打字,從而增加每個字符之間的延遲:

await page.type('input#name', 'Flavio', {delay: 100})

url()

獲取頁面URL

await page.url()

viewport()

獲取頁面視口

await page.viewport()

waitFor()

等待特定的事情發生。具有以下快捷功能:

  • waitForFunction
  • waitForNavigation
  • waitForRequest
  • waitForResponse
  • waitForSelector
  • waitForXPath

例子:

await page.waitFor(waitForNameToBeFilled)
const waitForNameToBeFilled = () => page.$('input#name').value != ''

頁面名稱空間

頁面對象使您可以訪問幾個不同的對象:

這些功能中的每一個都可以解鎖很多新功能。

keyboardmouse是您在嘗試使事情自動化時最常使用的工具。

例如,這是觸發輸入元素的方式(之前應選擇該元素):

await page.keyboard.type('hello!')

其他鍵盤方法是

  • keyboard.down()發送按鍵事件
  • keyboard.press()發送鍵盤按下信息,然後發送鍵盤按下信息(模擬正常的按鍵類型)。主要用於修飾鍵(shift,ctrl,cmd)
  • keyboard.sendCharacter()發送按鍵事件
  • keyboard.type()發送一個keydown,keypress和keyup事件
  • keyboard.up()發送按鍵事件

所有這些都將收到美國鍵盤佈局文件中定義的鍵盤鍵代碼:https://github.com/GoogleChrome/puppeteer/blob/master/lib/USKeyboardLayout.js。普通字符和數字按原樣鍵入,而特殊鍵具有定義它們的特殊代碼。

mouse提供4種方法:

  • mouse.click()模擬點擊:mousedownmouseup大事記
  • mouse.down()模擬一個mousedown事件
  • mouse.move()移動到不同的坐標
  • mouse.up()模擬一個mouseup事件