Puppeteer 相关介绍与安装不过多介绍,可通过以下链接进行学习
一、Puppeteer
开源地址
英文文档
中文社区
二、爬取动态网页
1. 需求
首先,了解下我们的需求: 爬取zoomcharts 文档中 Net Chart
目录下所有访问连接对应的页面,并保存到本地
2. 研究 ZoomCharts 文档页面结构
首先,我们得研究透 ZoomCharts 页面如何加载,以及左侧导航的 DOM 树结构,才好进行下一步操作
页面首次加载
页面首次加载,左侧导航第一个目录 Introduction
高亮,从控制台可看出,该元素增加了 active
类,同时 li[data-section="net-chart"]
节点下只有一个元素节点 a
点击 Net Chart
目录
点击 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 start --> // main 区域 <!-- end start--> 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文件
- 跳转每一个链接,下载需要的html到指定文件夹
- 当 HTML 中存在 img 时,下载所有图片
4. 总结
第一次使用Puppeteer也是磕磕绊绊,花费不少时间,期间也参考了不少文章,还需多多练习
代码仓库
代码仓库
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 柏菲·珞叔作品集《金色大厅2》限量开盘母带ORMCD[低速原抓WAV+CUE]
- Gareth.T《sad songs(Explicit)》[320K/MP3][29.03MB]
- Gareth.T《sad songs(Explicit)》[FLAC/分轨][152.85MB]
- 证声音乐图书馆《海风摇曳·盛夏爵士曲》[320K/MP3][63.06MB]
- 龚玥《金装龚玥HQCD》头版限量[WAV分轨]
- 李小春《吻别》萨克斯演奏经典[原抓WAV+CUE]
- 齐秦《辉煌30年24K珍藏版》2CD[WAV+CUE]
- 证声音乐图书馆《海风摇曳·盛夏爵士曲》[FLAC/分轨][321.47MB]
- 群星 《世界经典汽车音乐》 [WAV分轨][1G]
- 冷漠.2011 《冷漠的爱DSD》[WAV+CUE][1.2G]
- 陈明《流金岁月精逊【中唱】【WAV+CUE】
- 群星《Jazz-Ladies1-2爵士女伶1-2》HQCD/2CD[原抓WAV+CUE]
- 群星《美女私房歌》(黑胶)[WAV分轨]
- 郑源.2009《试音天碟》24BIT-96KHZ[WAV+CUE][1.2G]
- 飞利浦试音碟 《环球群星监听录》SACD香港版[WAV+CUE][1.1G]