Puppeteer保存html,Puppeteer 实战-爬取动态生成的网页

Puppeteer 相关介绍与安装不过多介绍,可通过以下链接进行学习

二、爬取动态网页

1. 需求

首先,了解下我们的需求: 爬取zoomcharts 文档中 Net Chart 目录下所有访问连接对应的页面,并保存到本地

ac63dad4e96964b929271da2f8ee1dae.png

2. 研究 ZoomCharts 文档页面结构

首先,我们得研究透 ZoomCharts 页面如何加载,以及左侧导航的 DOM 树结构,才好进行下一步操作

页面首次加载

2ab2beba8b000c6e00059c10fb20b777.png 页面首次加载,左侧导航第一个目录 Introduction 高亮,从控制台可看出,该元素增加了 active 类,同时 li[data-section="net-chart"] 节点下只有一个元素节点 a

点击 Net Chart 目录

20a4de52c0914b82f77af1025e3f17db.png

点击 Net Chart 目录, Net Chart 目录高亮,下拉显示子目录,查看控制台,其元素节点增加 active 类,并增加 ul 子元素节点, 此时,第一个子目录节点也只有一个子元素节点 a

结论

不难发现, 左侧目录是动态生成的,而不是静态写死的,只有点击父级目录,其子目录才会生成显示,同时,父级目录元素上的 drop 类表明存在子级目录

3. 编写主程序

通过上面分析,得出大概流程如下

从上到下,遍历 Net Chart 目录的 DOM 树,当找到 a.drop 的元素节点,模拟鼠标点击事件 click ,生成子目录节点

找到 Net Chart 目录下所有的 a 链接,生成一个数组

遍历数组,访问每一个子目录页面,保存页面的 html 文件到本地

接下来实现每个具体流程

项目初始化

安装 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); // 创建一个Browser 对象

try {

const page = await browser.newPage(); // 使用 Browser 创建 Page

page.setDefaultNavigationTimeout(600000);

// 监听 console

page.on('console', msg => {

for (let i = 0; i < msg.args().length; ++i) {

console.log(`${i}: ${msg.args()[i]}`);

}

});

// main 区域

console.log('服务正常结束')

} catch (error) {

console.log('服务出现错误:')

console.log(error)

} finally {

}

}

main()

复制代码

接下来所有代码都在 main 区域内完成, 完整代码可访问 github代码仓库 查看,下面仅列出每部分的思路

创建文件夹,用于保存爬取的文件

定义文件输出路径

根据路径生成文件夹

当文件夹已经存在,先删除,再新建

实现 Net Chart 目录下所有 a.drop 元素的点击事件

这部分涉及到DOM 操作, 只有在 page.evaluate() 中才能访问真实的 DOM 元素,同时,在 page.evaluate() 中不能直接调用外面定义的函数,可将函数传递进去,或将函数绑定到 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 函数需要在 page.evaluateOnNewDocument 函数中定义才能生效

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

}

}

})

复制代码

当Net Chart 目录下所有 a.drop 元素点击过后, Net Chart 目录下所有后代子目录都会加载生成,接下来操作就简单了

获取Net Chart 目录下所有 a 元素

通过 document.querySelectorAll() 查找到所有 a 元素,保存到数组

遍历数组,对数组每一项进行处理成 {href: '',text: ''} 对象

返回对象数组

遍历对象数组, 访问每一个链接,下载其HTML文件 img

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值