Puppeteer 爬取動(dòng)態(tài)生成的網(wǎng)頁(yè)實(shí)戰(zhàn)
Puppeteer 相關(guān)介紹與安裝不過(guò)多介紹,可通過(guò)以下鏈接進(jìn)行學(xué)習(xí)
一、Puppeteer
二、爬取動(dòng)態(tài)網(wǎng)頁(yè)
1. 需求
首先,了解下我們的需求: 爬取zoomcharts 文檔中 Net Chart 目錄下所有訪問(wèn)連接對(duì)應(yīng)的頁(yè)面,并保存到本地

2. 研究 ZoomCharts 文檔頁(yè)面結(jié)構(gòu)
首先,我們得研究透 ZoomCharts 頁(yè)面如何加載,以及左側(cè)導(dǎo)航的 DOM 樹(shù)結(jié)構(gòu),才好進(jìn)行下一步操作
頁(yè)面首次加載

頁(yè)面首次加載,左側(cè)導(dǎo)航第一個(gè)目錄 Introduction 高亮,從控制臺(tái)可看出,該元素增加了 active 類,同時(shí) li[data-section="net-chart"] 節(jié)點(diǎn)下只有一個(gè)元素節(jié)點(diǎn) a
點(diǎn)擊 Net Chart 目錄

點(diǎn)擊 Net Chart 目錄, Net Chart 目錄高亮,下拉顯示子目錄,查看控制臺(tái),其元素節(jié)點(diǎn)增加 active 類,并增加 ul 子元素節(jié)點(diǎn), 此時(shí),第一個(gè)子目錄節(jié)點(diǎn)也只有一個(gè)子元素節(jié)點(diǎn) a
結(jié)論
不難發(fā)現(xiàn), 左側(cè)目錄是動(dòng)態(tài)生成的,而不是靜態(tài)寫(xiě)死的,只有點(diǎn)擊父級(jí)目錄,其子目錄才會(huì)生成顯示,同時(shí),父級(jí)目錄元素上的 drop 類表明存在子級(jí)目錄
3. 編寫(xiě)主程序
通過(guò)上面分析,得出大概流程如下
- 從上到下,遍歷
Net Chart目錄的 DOM 樹(shù),當(dāng)找到a.drop的元素節(jié)點(diǎn),模擬鼠標(biāo)點(diǎn)擊事件click,生成子目錄節(jié)點(diǎn) - 找到
Net Chart目錄下所有的a鏈接,生成一個(gè)數(shù)組 - 遍歷數(shù)組,訪問(wèn)每一個(gè)子目錄頁(yè)面,保存頁(yè)面的 html 文件到本地
接下來(lái)實(shí)現(xiàn)每個(gè)具體流程
項(xiàng)目初始化
安裝 puppeteer , rimraf (文件夾操作時(shí)需用到)
npm i -S puppeteer rimraf
新建 test.js 文件并引入
const puppeteer = require('puppeteer');
const chalk = require('chalk');
const path = require('path');
const https = require('https');
const fs = require('fs');
const rm = require('rimraf');
const settings = {
headless: false
}
function resolve(dir, dir2 = '') {
return path.posix.join(__dirname, './', dir, dir2);
}
async function main () {
const browser = await puppeteer.launch(settings); // 創(chuàng)建一個(gè)Browser 對(duì)象
try {
const page = await browser.newPage(); // 使用 Browser 創(chuàng)建 Page
page.setDefaultNavigationTimeout(600000);
// 監(jiān)聽(tīng) console
page.on('console', msg => {
for (let i = 0; i < msg.args().length; ++i) {
console.log(`${i}: ${msg.args()[i]}`);
}
});
<!-- main start -->
// main 區(qū)域
<!-- end start-->
console.log('服務(wù)正常結(jié)束')
} catch (error) {
console.log('服務(wù)出現(xiàn)錯(cuò)誤:')
console.log(error)
} finally {
}
}
main()
接下來(lái)所有代碼都在 main 區(qū)域內(nèi)完成, 完整代碼可訪問(wèn)github代碼倉(cāng)庫(kù) 查看,下面僅列出每部分的思路
創(chuàng)建文件夾,用于保存爬取的文件
- 定義文件輸出路徑
- 根據(jù)路徑生成文件夾
- 當(dāng)文件夾已經(jīng)存在,先刪除,再新建
實(shí)現(xiàn) Net Chart 目錄下所有 a.drop 元素的點(diǎn)擊事件
這部分涉及到DOM 操作, 只有在 page.evaluate() 中才能訪問(wèn)真實(shí)的 DOM 元素,同時(shí),在 page.evaluate() 中不能直接調(diào)用外面定義的函數(shù),可將函數(shù)傳遞進(jìn)去,或?qū)⒑瘮?shù)綁定到 window 對(duì)象上
await page.evaluate(async () => {
const rootNode = document.querySelector('#menu > ul > li:nth-child(5) > ul > li:nth-child(5)');
await window.walkDOM(rootNode)
})
此時(shí),綁定到 window 對(duì)象上的 walkDOM 函數(shù)需要在 page.evaluateOnNewDocument 函數(shù)中定義才能生效
await page.evaluateOnNewDocument(() => {
// 遍歷DOM
window.walkDOM = (node) => {
if (node === null) {
return
}
if (node.tagName === 'A' && node.className.indexOf('drop') > -1) {
node.click() // 點(diǎn)擊事件
}
node = node.firstElementChild
while (node) {
walkDOM(node)
node = node.nextElementSibling
}
}
})
當(dāng)Net Chart 目錄下所有 a.drop 元素點(diǎn)擊過(guò)后, Net Chart 目錄下所有后代子目錄都會(huì)加載生成,接下來(lái)操作就簡(jiǎn)單了
獲取Net Chart 目錄下所有 a 元素
- 通過(guò)
document.querySelectorAll()查找到所有a元素,保存到數(shù)組 - 遍歷數(shù)組,對(duì)數(shù)組每一項(xiàng)進(jìn)行處理成
{href: '',text: ''}對(duì)象 - 返回對(duì)象數(shù)組
遍歷對(duì)象數(shù)組, 訪問(wèn)每一個(gè)鏈接,下載其HTML文件
- 跳轉(zhuǎn)每一個(gè)鏈接,下載需要的html到指定文件夾
- 當(dāng) HTML 中存在 img 時(shí),下載所有圖片
4. 總結(jié)
第一次使用Puppeteer也是磕磕絆絆,花費(fèi)不少時(shí)間,期間也參考了不少文章,還需多多練習(xí)
代碼倉(cāng)庫(kù)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解基于node的前端項(xiàng)目編譯時(shí)內(nèi)存溢出問(wèn)題
本篇文章主要介紹了基于node的前端項(xiàng)目編譯時(shí)內(nèi)存溢出問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
Node.js 利用cheerio制作簡(jiǎn)單的網(wǎng)頁(yè)爬蟲(chóng)示例
本篇文章主要介紹了Node.js 利用cheerio制作簡(jiǎn)單的網(wǎng)頁(yè)爬蟲(chóng)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
Koa從零搭建到Api實(shí)現(xiàn)項(xiàng)目的搭建方法
這篇文章主要介紹了Koa從零搭建到Api實(shí)現(xiàn)項(xiàng)目的搭建方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
NodeJs版本過(guò)高無(wú)法啟動(dòng)Vue項(xiàng)目報(bào)錯(cuò)的幾種解決方法
在開(kāi)發(fā)vue項(xiàng)目時(shí),我們通常使用nodejs作為項(xiàng)目的運(yùn)行環(huán)境,但是有時(shí)候,由于nodejs版本過(guò)高,可能會(huì)導(dǎo)致vue項(xiàng)目啟動(dòng)報(bào)錯(cuò),這篇文章主要給大家介紹了關(guān)于NodeJs版本過(guò)高無(wú)法啟動(dòng)Vue項(xiàng)目報(bào)錯(cuò)的幾種解決方法,需要的朋友可以參考下2023-12-12
windows系統(tǒng)上完全卸載并重裝Node的步驟(親測(cè)可用)
對(duì)于Windows平臺(tái)來(lái)說(shuō),所有的應(yīng)用程序,其安裝卸載都是一樣的,node.js也不例外,但是還是很多用戶不明白,下面這篇文章主要給大家介紹了關(guān)于windows系統(tǒng)上完全卸載并重裝Node的步驟,需要的朋友可以參考下2023-03-03
Windows 系統(tǒng)下安裝和部署Egret的開(kāi)發(fā)環(huán)境
Egret基于TypeScript開(kāi)發(fā)的,而TypeScript編譯工具tsc是基于Node.js 開(kāi)發(fā)的。所以在安裝過(guò)程中,我們先需要對(duì)于基礎(chǔ)支持工具進(jìn)行安裝。2014-07-07
3分鐘快速搭建nodejs本地服務(wù)器方法運(yùn)行測(cè)試html/js
本篇文章主要介紹了3分鐘快速搭建nodejs本地服務(wù)器方法運(yùn)行測(cè)試html/js,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04

