從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>(() => {
<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
與傳遞對象width
和height
特性。
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 != ''
頁面名稱空間
頁面對象使您可以訪問幾個不同的對象:
這些功能中的每一個都可以解鎖很多新功能。
keyboard
和mouse
是您在嘗試使事情自動化時最常使用的工具。
例如,這是觸發輸入元素的方式(之前應選擇該元素):
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()
模擬點擊:mousedown
和mouseup
大事記mouse.down()
模擬一個mousedown
事件mouse.move()
移動到不同的坐標mouse.up()
模擬一個mouseup
事件