Node爬蟲工具Puppeteer入門教程實(shí)踐
【Puppeteer概要】
- Puppeteer 是一個(gè) Node 庫,它提供了一個(gè)高級 API 來通過 DevTools 協(xié)議控制 Chromium 或 Chrome。 Puppeteer API 是分層次的,反映了瀏覽器結(jié)構(gòu)。
- Puppeteer 使用 DevTools 協(xié)議 與瀏覽器進(jìn)行通信。
- Browser 實(shí)例可以擁有瀏覽器上下文。
- BrowserContext 實(shí)例定義了一個(gè)瀏覽會(huì)話并可擁有多個(gè)頁面。
- Page 至少有一個(gè)框架:主框架。 可能還有其他框架由 iframe 或 框架標(biāo)簽 創(chuàng)建。
- frame 至少有一個(gè)執(zhí)行上下文 - 默認(rèn)的執(zhí)行上下文 - 框架的 JavaScript 被執(zhí)行。 一個(gè)框架可能有額外的與 擴(kuò)展 關(guān)聯(lián)的執(zhí)行上下文。
- Worker 具有單一執(zhí)行上下文,并且便于與 WebWorkers 進(jìn)行交互。
【Puppeteer 錯(cuò)誤處理】
Error handling
- 如果
Puppeteer
方法無法執(zhí)行一個(gè)請求,就會(huì)拋出一個(gè)錯(cuò)誤。例如,page.waitForSelector(selector[, options])
選擇器如果在給定的時(shí)間范圍內(nèi)無法匹配節(jié)點(diǎn),就會(huì)失敗。 對于某些類型的錯(cuò)誤,Puppeteer
使用特定的錯(cuò)誤類處理。這些類可以通過require('puppeteer/Errors')
獲得。 支持的類列表:
TimeoutError
一個(gè)處理超時(shí)錯(cuò)誤的例子:
const { TimeoutError } = require('puppeteer/Errors'); // ... try { await page.waitForSelector('.foo'); } catch(e) { if (e instanceof TimeoutError) { // 如果超時(shí),做一些處理。 } }
Puppeteer Working with Chrome Extensions
Puppeteer
可以用來測試Chrome
擴(kuò)展
注意
Chrome / Chromium
擴(kuò)展當(dāng)前只能在非無頭模式下使用。
下面的代碼用來處理擴(kuò)展的 background page
,該擴(kuò)展的代碼在 ./my-extension
:
const puppeteer = require('puppeteer'); (async() = > { const pathToExtension = require('path').join(__dirname, 'my-extension'); const browser = puppeteer.launch({ headless: false, args: [`--disable - extensions - except = $ { pathToExtension }`, `--load - extension = $ { pathToExtension }`] }); const targets = await browser.targets(); const backgroundPageTarget = targets.find(target = >target.type() === 'background_page'); const backgroundPage = await backgroundPageTarget.page(); // 像處理任何其他頁面一樣測試背景頁面。 await browser.close();})();
【Puppeteer class:puppeteer】
Puppeteer
模塊提供了一種啟動(dòng)Chromium
實(shí)例的方法。 下面就是使用Puppeteer
進(jìn)行自動(dòng)化的一個(gè)典型示例:
const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser = >{ const page = await browser.newPage(); await page.goto('https://www.google.com'); // 其他操作... await browser.close();});
Methods
- puppeteer.connect(options)v0.9.0
- puppeteer.createBrowserFetcher([options])v0.9.0
- puppeteer.defaultArgs([options])v0.9.0
- puppeteer.executablePath()v0.9.0
- puppeteer.launch([options])v0.9.0
Methods
puppeteer.connect(options)v0.9.0
options
<Object>
browserWSEndpoint
<string>
一個(gè) 瀏覽器 websocket 端點(diǎn)鏈接。ignoreHTTPSErrors
<boolean>
是否在導(dǎo)航期間忽略 HTTPS 錯(cuò)誤. 默認(rèn)是false。
defaultViewport
<?Object> 為每個(gè)頁面設(shè)置一個(gè)默認(rèn)視口大小。默認(rèn)是800x600
。如果為 null 的話就禁用視圖口。width
<number>
頁面寬度像素。height
<number>
頁面高度像素。deviceScaleFactor
<number>
設(shè)置設(shè)備的縮放(可以認(rèn)為是 dpr)。默認(rèn)是1。
isMobile
<boolean>
是否在頁面中設(shè)置了meta viewport
標(biāo)簽。默認(rèn)是false。
hasTouch``<boolean>
指定viewport是否支持觸摸事件。默認(rèn)是false。
isLandscape
<boolean>
指定視口是否處于橫向模式。默認(rèn)是false。
slowMo
<number>
將 Puppeteer 操作減少指定的毫秒數(shù)。這樣你就可以看清發(fā)生了什么,這很有用。returns
:<Promise<Browser>>
此方法將Puppeteer
添加到已有的Chromium
實(shí)例。
puppeteer.createBrowserFetcher([options])v0.9.0
options
<Object>
host
<string>
要使用的下載主機(jī). 默認(rèn)是https://storage.googleapis.com。
path
<string>
下載文件夾的路徑. 默認(rèn)是<root>
/.local-chromium,<root>
是 puppeteer 的包根目錄。platform
<string>
可能的值有:mac, win32, win64, linux
。默認(rèn)是當(dāng)前平臺
。returns
:<BrowserFetcher>
puppeteer.defaultArgs([options])v0.9.0
options
<Object>
設(shè)置瀏覽器可選項(xiàng)。有一下字段:headless
<boolean>
是否在 無頭模式 下運(yùn)行瀏覽器。默認(rèn)是true
除非devtools
選項(xiàng)是true。
args
<Array<string>>
傳遞給瀏覽器實(shí)例的其他參數(shù)??梢?在這 找到 Chromium 標(biāo)志列表。userDataDir
<string>
用戶數(shù)據(jù)目錄 的路徑。devtools
<boolean>
是否為每個(gè)選項(xiàng)卡自動(dòng)打開DevTools
面板。如果這個(gè)選項(xiàng)是true
的話,headless
選項(xiàng)將被設(shè)置為false。
returns
:<Array<string>>
Chromium 啟動(dòng)時(shí)使用的默認(rèn)參數(shù)。
puppeteer.executablePath()v0.9.0
returns
:<string>
Puppeteer 希望找到綁定的Chromium
的路徑。- 如果使用
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD
跳過下載,則Chromium
可能不存在。
puppeteer.launch([options])v0.9.0
options
<Object>
在瀏覽器上設(shè)置的一組可配置選項(xiàng)。 有以下字段:ignoreHTTPSErrors
<boolean>
是否在導(dǎo)航期間忽略HTTPS
錯(cuò)誤. 默認(rèn)是false。
headless
<boolean>
是否以 無頭模式 運(yùn)行瀏覽器。默認(rèn)是true,除非
devtools
選項(xiàng)是true。
executablePath
<string>
可運(yùn)行 Chromium 或 Chrome 可執(zhí)行文件的路徑,而不是綁定的Chromium。如果
executablePath
是一個(gè)相對路徑,那么他相對于 當(dāng)前工作路徑 解析。slowMo
<number>
將 Puppeteer 操作減少指定的毫秒數(shù)。這樣你就可以看清發(fā)生了什么,這很有用。defaultViewport
<?Object>
為每個(gè)頁面設(shè)置一個(gè)默認(rèn)視口大小。默認(rèn)是800x600
。如果為 null 的話就禁用視圖口。width
<number>
頁面寬度像素。height
<number>
頁面高度像素。deviceScaleFactor
<number>
設(shè)置設(shè)備的縮放(可以認(rèn)為是dpr
)。默認(rèn)是1
。isMobile
<boolean>
是否在頁面中設(shè)置了meta viewport
標(biāo)簽。默認(rèn)是false。
hasTouch``<boolean>
指定viewport是否支持觸摸事件。默認(rèn)是false。
isLandscape
<boolean>
指定視口是否處于橫向模式。默認(rèn)是false。
args
<Array<string>>
傳遞給瀏覽器實(shí)例的其他參數(shù)。 這些參數(shù)可以參考 這里。- ignoreDefaultArgs <(boolean|
<Array<string>>
)> 如果是true
,那就不要使用puppeteer.defaultArgs()
。 如果給出了數(shù)組,則過濾掉給定的默認(rèn)參數(shù)。這個(gè)選項(xiàng)請謹(jǐn)慎使用。默認(rèn)為false
。 handleSIGINT
<boolean>
Ctrl-C 關(guān)閉瀏覽器進(jìn)程。默認(rèn)是true
。handleSIGTERM
<boolean>
關(guān)閉 SIGTERM 上的瀏覽器進(jìn)程。默認(rèn)是true
。handleSIGHUP
<boolean>
關(guān)閉 SIGHUP 上的瀏覽器進(jìn)程。默認(rèn)是true
.timeout
<number>
等待瀏覽器實(shí)例啟動(dòng)的最長時(shí)間(以毫秒為單位)。默認(rèn)是30000 (30 秒)
. 通過 0 來禁用超時(shí)。dumpio
<boolean>
是否將瀏覽器進(jìn)程標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸入到process.stdout 和 process.stderr
中。默認(rèn)是false。
userDataDir
<string>
用戶數(shù)據(jù)目錄 路徑。env
<Object>
指定瀏覽器可見的環(huán)境變量。默認(rèn)是process.env
。devtools
<boolean>
是否為每個(gè)選項(xiàng)卡自動(dòng)打開DevTools面板。如果這個(gè)選項(xiàng)是true,headless
選項(xiàng)將會(huì)設(shè)置成false
。pipe
<boolean>
通過管道而不是WebSocket連接到瀏覽器。默認(rèn)是false
。returns
:<Promise<Browser>>
瀏覽器實(shí)例支持Promise
。
這個(gè)方法結(jié)合了下面3個(gè)步驟:
使用 puppeteer.defaultArgs() 作為一組默認(rèn)值來啟動(dòng) Chromium。
啟動(dòng)瀏覽器并根據(jù) executablePath
,handleSIGINT
,dumpio
和其他選項(xiàng)開始管理它的進(jìn)程。 創(chuàng)建一個(gè) Browser
類的實(shí)例,并根據(jù) defaultViewport
,slowMo
和 ignoreHTTPSErrors
初始化它。 ignoreDefaultArgs
選項(xiàng)可用于自定義(1)步驟的行為。 例如,要從參數(shù)中過濾掉 --mute-audio
:
const browser = await puppeteer.launch({ ignoreDefaultArgs: ['--mute-audio'] }); 復(fù)制代碼
Puppeteer 瀏覽器
- extends:
EventEmitter
當(dāng)Puppeteer
連接到一個(gè)Chromium
實(shí)例的時(shí)候會(huì)通過puppeteer.launch
或puppeteer.connect
創(chuàng)建一個(gè)Browser
對象。 下面是使用Browser
創(chuàng)建Page
的例子
const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser = >{ const page = await browser.newPage(); await page.goto('https://example.com'); await browser.close(); });
- 一個(gè)斷開連接和重連到 Browser 的例子:
const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser = >{ // 存儲(chǔ)節(jié)點(diǎn)以便能重新連接到 Chromium const browserWSEndpoint = browser.wsEndpoint(); // 從 Chromium 斷開和 puppeteer 的連接 browser.disconnect(); // 使用節(jié)點(diǎn)來重新建立連接 const browser2 = await puppeteer.connect({browserWSEndpoint}); // 關(guān)閉 Chromium await browser2.close();});
Puppeteer 頁面
Page
提供操作一個(gè)tab
頁或者extension
background
page
的方法。一個(gè)Browser
實(shí)例可以有多個(gè)Page
實(shí)例。 下面的例子創(chuàng)建一個(gè)Page
實(shí)例,導(dǎo)航到一個(gè)url
,然后保存截圖:
const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser = >{ const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({ path: 'screenshot.png' }); await browser.close(); });
- Page會(huì)觸發(fā)多種事件(下面描述的),可以用 node原生的方法 來捕獲處理,比如
on
,once
或者removeListener。
下面的例子捕獲了一個(gè)page
實(shí)例的load
事件,打印了一句話:
page.once('load', () => console.log('Page loaded!'));
- 可以用
removeListener
取消對事件的監(jiān)聽:
function logRequest(interceptedRequest) { console.log('A request was made:', interceptedRequest.url()); } page.on('request', logRequest); // 一段時(shí)間后...page.removeListener('request', logRequest);
Methods
page.$(selector)v0.9.0
selector
<string>
選擇器 返回:<Promise<?ElementHandle>>
此方法在頁面內(nèi)執(zhí)行
document.querySelector
。如果沒有元素匹配指定選擇器,返回值是 null。page.mainFrame().$(selector) 的簡寫。
page.$$(selector)v0.9.0
selector
<string>
選擇器返回:
<Promise<Array<ElementHandle>>>
此方法在頁面內(nèi)執(zhí)行
document.querySelectorAll
。如果沒有元素匹配指定選擇器,返回值是 []。page.mainFrame().$$(selector)
的簡寫。
page.waitForSelector(".index-content .click-zoom a")
- 等待頁面元素加載完成
await page.waitForSelector(".index-content .click-zoom a")
page.waitFor(1000)
- 等待1000毫秒執(zhí)行
await page.waitFor(1000)
page.click('.btn')
await page.click('.btn')
- 點(diǎn)擊class 為btn元素
page.evaluate
- 執(zhí)行原生js
await page.evaluate(() => { document.getElementById("HD_CheckIn").value = "2020-07-11"; })
示例
- 代碼執(zhí)行
- 安裝 puppeteer 依賴包
- node xxx.js 運(yùn)行js
/** * 爬取游戲站數(shù)據(jù) https://game.pipajam.com/ */ const fs = require('fs') const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false, args: ['--start-maximized', '--disable-infobars'], width: 1600, height: 900 }); // 1、 創(chuàng)建兩個(gè)頁面 const page = await browser.newPage(); const page2 = await browser.newPage(); // 2、進(jìn)入首頁 await page.goto( 'https://game.pipajam.com/' ); // 3、等待頁面游戲數(shù)據(jù)元素加載完成 await page.waitForSelector(".index-content .click-zoom a") // 4、獲取所以游戲鏈接 游戲名稱 const list = await page.$$eval(".index-content .click-zoom a", (el => el.map(el => ([el.href, el.getElementsByTagName('h6')[0].innerText])))); console.log(list); let len = list.length, index = 0, data = [] // 5、調(diào)用函數(shù) 組裝數(shù)據(jù) mainFun() async function mainFun () { try { // 6、開啟page2 頁面 獲取游戲詳情數(shù)據(jù) await page2.goto( list[index][0],{ timeout: 0 } ); // 7、等待詳情卡片加載完成 await page2.waitForSelector(".play-game-card .play-game-card-center") // 8、獲取游戲鏈接地址 圖片地址 const item = await page2.$eval(".play-game-card .play-game-card-center", (el => [el.getElementsByTagName('p')[0].innerHTML, el.getElementsByTagName('img')[0].src])); await page2.click('.play-game-card .play-game-card-center a') const url = await page2.evaluate(param => window.location.href, "參數(shù)"); // 9、組裝數(shù)據(jù) data.push({ description: item[0], img: item[1], instructton: "", keyfeatures: "", name: list[index][1], published: "Mon Oct 08 2018", tags: [], url, type: 'Children\'s intelligence', }) console.log('以寫入第' + (index+1) + '數(shù)據(jù)。'); // 10、獲取所以游戲數(shù)據(jù) 并寫入指定json 文件 ++index < len ? mainFun() : fs.writeFile('../../json/Game/pipajam.json', JSON.stringify(data), () => {}) } catch (error) { console.log(error, 'err') } } })();
到此這篇關(guān)于Node爬蟲工具Puppeteer入門教程實(shí)踐的文章就介紹到這了,更多相關(guān)Node Puppeteer入門內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Express+Nodejs 下的登錄攔截實(shí)現(xiàn)代碼
本篇文章主要介紹了Express+Nodejs 下的登錄攔截實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07Node.js使用Express創(chuàng)建Web項(xiàng)目詳細(xì)教程
如果需要入門使用node.js進(jìn)行web開發(fā),正在學(xué)習(xí) nodejs web開發(fā)指南 的和想快速了解node.js web開發(fā)模式的朋友,相信本文是有一定幫助意義的。2017-03-03node.js文件上傳重命名以及移動(dòng)位置的示例代碼
本篇文章主要介紹了node.js文件上傳重命名以及移動(dòng)位置的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01Nodejs多站點(diǎn)切換Htpps協(xié)議詳解及簡單實(shí)例
這篇文章主要介紹了Nodejs多站點(diǎn)切換Htpps協(xié)議詳解及簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02node.js 用socket實(shí)現(xiàn)聊天的示例代碼
本篇文章主要介紹了node.js 用socket實(shí)現(xiàn)聊天的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10