Puppeteer 爬取動態(tài)生成的網(wǎng)頁實戰(zhàn)
Puppeteer 相關(guān)介紹與安裝不過多介紹,可通過以下鏈接進行學(xué)習(xí)
一、Puppeteer
二、爬取動態(tài)網(wǎng)頁
1. 需求
首先,了解下我們的需求: 爬取zoomcharts 文檔中 Net Chart
目錄下所有訪問連接對應(yīng)的頁面,并保存到本地
2. 研究 ZoomCharts 文檔頁面結(jié)構(gòu)
首先,我們得研究透 ZoomCharts 頁面如何加載,以及左側(cè)導(dǎo)航的 DOM 樹結(jié)構(gòu),才好進行下一步操作
頁面首次加載
頁面首次加載,左側(cè)導(dǎo)航第一個目錄 Introduction
高亮,從控制臺可看出,該元素增加了 active
類,同時 li[data-section="net-chart"]
節(jié)點下只有一個元素節(jié)點 a
點擊 Net Chart
目錄
點擊 Net Chart
目錄, Net Chart
目錄高亮,下拉顯示子目錄,查看控制臺,其元素節(jié)點增加 active
類,并增加 ul
子元素節(jié)點, 此時,第一個子目錄節(jié)點也只有一個子元素節(jié)點 a
結(jié)論
不難發(fā)現(xiàn), 左側(cè)目錄是動態(tài)生成的,而不是靜態(tài)寫死的,只有點擊父級目錄,其子目錄才會生成顯示,同時,父級目錄元素上的 drop
類表明存在子級目錄
3. 編寫主程序
通過上面分析,得出大概流程如下
- 從上到下,遍歷
Net Chart
目錄的 DOM 樹,當(dāng)找到a.drop
的元素節(jié)點,模擬鼠標(biāo)點擊事件click
,生成子目錄節(jié)點 - 找到
Net Chart
目錄下所有的a
鏈接,生成一個數(shù)組 - 遍歷數(shù)組,訪問每一個子目錄頁面,保存頁面的 html 文件到本地
接下來實現(xiàn)每個具體流程
項目初始化
安裝 puppeteer
, rimraf
(文件夾操作時需用到)
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)建一個Browser 對象 try { const page = await browser.newPage(); // 使用 Browser 創(chuàng)建 Page page.setDefaultNavigationTimeout(600000); // 監(jiān)聽 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)錯誤:') console.log(error) } finally { } } main()
接下來所有代碼都在 main
區(qū)域內(nèi)完成, 完整代碼可訪問github代碼倉庫 查看,下面僅列出每部分的思路
創(chuàng)建文件夾,用于保存爬取的文件
- 定義文件輸出路徑
- 根據(jù)路徑生成文件夾
- 當(dāng)文件夾已經(jīng)存在,先刪除,再新建
實現(xiàn) Net Chart 目錄下所有 a.drop
元素的點擊事件
這部分涉及到DOM 操作, 只有在 page.evaluate()
中才能訪問真實的 DOM
元素,同時,在 page.evaluate()
中不能直接調(diào)用外面定義的函數(shù),可將函數(shù)傳遞進去,或?qū)⒑瘮?shù)綁定到 window
對象上
await page.evaluate(async () => { const rootNode = document.querySelector('#menu > ul > li:nth-child(5) > ul > li:nth-child(5)'); await window.walkDOM(rootNode) })
此時,綁定到 window
對象上的 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() // 點擊事件 } node = node.firstElementChild while (node) { walkDOM(node) node = node.nextElementSibling } } })
當(dāng)Net Chart 目錄下所有 a.drop
元素點擊過后, Net Chart
目錄下所有后代子目錄都會加載生成,接下來操作就簡單了
獲取Net Chart 目錄下所有 a 元素
- 通過
document.querySelectorAll()
查找到所有a
元素,保存到數(shù)組 - 遍歷數(shù)組,對數(shù)組每一項進行處理成
{href: '',text: ''}
對象 - 返回對象數(shù)組
遍歷對象數(shù)組, 訪問每一個鏈接,下載其HTML文件
- 跳轉(zhuǎn)每一個鏈接,下載需要的html到指定文件夾
- 當(dāng) HTML 中存在 img 時,下載所有圖片
4. 總結(jié)
第一次使用Puppeteer也是磕磕絆絆,花費不少時間,期間也參考了不少文章,還需多多練習(xí)
代碼倉庫
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Node.js 利用cheerio制作簡單的網(wǎng)頁爬蟲示例
本篇文章主要介紹了Node.js 利用cheerio制作簡單的網(wǎng)頁爬蟲示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03windows系統(tǒng)上完全卸載并重裝Node的步驟(親測可用)
對于Windows平臺來說,所有的應(yīng)用程序,其安裝卸載都是一樣的,node.js也不例外,但是還是很多用戶不明白,下面這篇文章主要給大家介紹了關(guān)于windows系統(tǒng)上完全卸載并重裝Node的步驟,需要的朋友可以參考下2023-03-03Windows 系統(tǒng)下安裝和部署Egret的開發(fā)環(huán)境
Egret基于TypeScript開發(fā)的,而TypeScript編譯工具tsc是基于Node.js 開發(fā)的。所以在安裝過程中,我們先需要對于基礎(chǔ)支持工具進行安裝。2014-07-073分鐘快速搭建nodejs本地服務(wù)器方法運行測試html/js
本篇文章主要介紹了3分鐘快速搭建nodejs本地服務(wù)器方法運行測試html/js,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-04-04