node爬虫puppeteer使用
文章目录
- node 爬虫 puppeteer 使用
- 记录一个实战 demo
- 开发先看文档
- 启动浏览器
- 官网的入门 demo
- puppeteer.launch
- page.goto
- 获取页面上的元素
- 剩下就是业务逻辑的问题了
- 实现 ping 方法
- await 锦上添花
- 项目中的 loading 效果
- 完整的项目代码
- index.js
- utils/index.js
- 总结
node 爬虫 puppeteer 使用
puppeteer 是一个基于 Chromium
的 node 爬虫框架。其厉害之处就是他具备浏览器的所有功能,并且通过 nodejs 就可以控制。完美实现我们要的爬虫效果 (后面附有完整代码~)
安装 puppeteer 时还会同步下载 Chromium 。网络不好的直接用 cnpm 下载即可。
当然官方也有一个另外的包,原话如下:
Since version 1.7.0 we publish the puppeteer-core package, a version of Puppeteer that doesn't download any browser by default.
意思大概就是使用 puppeteer-core
就可以使用 puppeteer
核心功能,而不用安装完整的浏览器。这次我还没用上,下次用上了在细说~
记录一个实战 demo
一个 node 命令行的小工具,原理是从 https://ping.chinaz.com/ 网站获取对应的网址的 IP 信息和请求时长,然后在从本地 Ping 对应的 IP,找到网址的最佳节点
运行效果:
PS: 为啥不直接用这个网站查,还得自己写一次?因为网站查出来的 IP 显示是可以的,可是本地 ping 不一定通,总不能一个个尝试把,所以这个工具就诞生了~
至于为什么要用到 puppeteer
?是因为这个网站没对外提供 api,所以只能从请求的界面上,获取我们要用的信息
开发先看文档
官方文档 pptr
如果第一次打不开呢,就把 185.199.110.133 raw.githubusercontent.com
加到 host 文件去,因为文档是从 github 加载的。而且把 netword
面板的 禁用缓存 去掉。
启动浏览器
官网的入门 demo
const puppeteer = require('puppeteer');(async () => {// 创建一个浏览器对象const browser = await puppeteer.launch()// 打开一个新的页面const page = await browser.newPage()// 设置页面的URLawait page.goto('https://www.google.com')// other actions...// 最后关闭浏览器(如果不关闭,node程序也不会结束的)await browser.close()
})()
puppeteer.launch
先看启动的文档把~ launch 文档
关于 launch 我只用到了一个参数, headless 是否不显示
浏览器界面
一开始的调试模式,我还是选择了打开浏览器界面
const browser = await puppeteer.launch({headless: false // 是否 不显示浏览器界面
})
page.goto
await page.goto('https://ping.chinaz.com/www.baidu.com', {timeout: 0, // 不限制超时时间waitUntil: 'networkidle0'
})
page 就是当前的 tab 标签页了。page.goto 文档
打开界面后,https://ping.chinaz.com/ 如果后面有网址的话,会自动开始请求,所以我要做的就是,等他们完全请求完成,我才开始获取内容
goto 提供了几个选项,一个是等待多少 s 后,页面没加载完,就算 GG 了。除非设置 -1 就会一直等下去
第二个就是 waitUntil
我用的是networkidle0
。就是 500 毫秒内没有任何请求了,就会继续往下执行
获取页面上的元素
平时我们都会在控制台用 $
运算符,进行查询。puppeteer 也提供了类似的功能,而且分的更加细了。
页面选择器 文档
可以看到上面有 page.$
和 page.$$
很多 api 都会有 $
和 $$
区别。其实都是同一个意思,用 $
的话只会查询匹配的第一个元素,而用 $$
类的 api,会帮你把对应元素都查出来,变成一个数组元素
page.$$(selector)
和 page.$$eval(selector, pageFunction[, ...args])
也很类似,都是查询元素
不过 page.$$
是查询到了所有匹配的节点,然后给你提供对应的方法,比如你可以查到那些节点后在执行 page.$eval
page.$$eval
则是最贴近我们的查询对应节点,然后后面的回调函数可以操作 node 节点
所以,我用了 page.$$eval
查询表格中的所有的数据,在回调函数中再去操作每一项的 innerText
。
let list = await page.$$eval('#speedlist .listw', options =>options.map(option => {let [city, ip, ipaddress, responsetime, ttl] = option.innerText.split(/[\n]/g)return { city, ip, ipaddress, responsetime, ttl }})
)
剩下就是业务逻辑的问题了
实现 ping 方法
ping 方法的实现特别的简单粗暴,就是引入 npm - ping
ping.sys.probe(IP地址,回调函数)
所以下面基于这个异步方法封装了一下,传入 IP,计算本机具体 ping 的时间。并且用 Promise 封装一下,方便我们使用 async 和 await
const pingIp = ip =>new Promise((resolve, reject) => {let startTime = new Date().getTime()ping.sys.probe(ip, function(isAlive) {if (isAlive) {resolve({ip: ip,time: new Date().getTime() - startTime})} else {reject({ip: ip,time: -1})}})})
await 锦上添花
如果我们的 Promise 返回的是 reject 。通常来说我们只能用 try/catch
去处理。这可不太优雅,可以参考以前的文章 [http://jioho.gitee.io/blog/JavaScript/%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E5%A4%84%E7%90%86async%E6%8A%9B%E5%87%BA%E7%9A%84%E9%94%99%E8%AF%AF.html)
const awaitWrap = promise => {return promise.then(data => [data, null]).catch(err => [null, err])
}
项目中的 loading 效果
由于整套过程下来比较漫长,需要等待时间比较多,所以有一个好的 loading 提示非常重要。于是使用 npm - ora
在各个地方加上 loading 和对应的提示
完整的项目代码
依赖项:
npm 包名 | 作用 |
---|---|
ora | 友好的 loading 效果 |
puppeteer | 爬虫框架 |
ping | node 进行 ping 的方法 |
index.js
const ora = require('ora')
let inputUrl = process.argv[2]
if (!inputUrl) {ora().warn('请输入需要判断的链接')process.exit()
}const puppeteer = require('puppeteer')const { awaitWrap, pingIp, moveHttp } = require('./utils')let url = moveHttp(inputUrl)const BaiseUrl = 'https://ping.chinaz.com/';(async () => {const init = ora('初始化浏览器环境').start()const browser = await puppeteer.launch({headless: true // 是否不显示浏览器界面})init.succeed('初始化完成')const loading = ora(`正在解析 ${url}`).start()const page = await browser.newPage() // 创建一个新页面await page.goto(BaiseUrl + url, {timeout: 0, // 不限制超时时间waitUntil: 'networkidle0'})loading.stop()let list = await page.$$eval('#speedlist .listw', options =>options.map(option => {let [city, ip, ipaddress, responsetime, ttl] = option.innerText.split(/[\n]/g)return { city, ip, ipaddress, responsetime, ttl }}))if (list.length == 0) {ora().fail('请输入正确的网址或IP')process.exit()}ora().succeed('获取IP地址完成,尝试连接IP地址')let ipObj = {}let success = []let failList = []let fast = Infinitylet fastIp = ''for (let i = 0; i < list.length; i++) {let item = list[i]let time = parseInt(item.responsetime)if (!isNaN(time) && !ipObj[item.ip]) {const tryIp = ora(`尝试 ${item.ip}`).start()let [res, error] = await awaitWrap(pingIp(item.ip))if (!error) {success.push(res.ip)if (res.time < fast) {fast = res.timefastIp = res.ip}tryIp.succeed(`${res.ip} 连接成功,耗时:${res.time}ms`)} else {failList.push(error.ip)tryIp.fail(`${error.ip} 连接失败`)}ipObj[item.ip] = time}}if (success.length > 0) {ora().succeed(`请求成功:${JSON.stringify(success)}`)}if (failList.length > 0) {ora().fail(`请求失败:${JSON.stringify(failList)}`)}if (fastIp) {ora().info(`推荐节点: ${fastIp},时间: ${fast}ms`)ora().info(`host配置: ${fastIp} ${url}`)}browser.close() // 关闭浏览器
})()
utils/index.js
var ping = require('ping')module.exports = {awaitWrap: promise => {return promise.then(data => [data, null]).catch(err => [null, err])},pingIp: ip =>new Promise((resolve, reject) => {let startTime = new Date().getTime()ping.sys.probe(ip, function(isAlive) {if (isAlive) {resolve({ip: ip,time: new Date().getTime() - startTime})} else {reject({ip: ip,time: -1})}})}),moveHttp: val => {val = val.replace(/http(s)?:\/\//i, '')var temp = val.split('/')if (temp.length <= 2) {if (val[val.length - 1] == '/') {val = val.substring(0, val.length - 1)}}return val}
}
总结
整个项目下来,最主要的就是打开浏览器,和学会看文档中的各个事件,这里展示的只是浏览器的网络请求的等待,还有很多其他的方法
- 比如等到某个节点出现的回调
- 拦截请求
- 等待某个请求结束后回调
- 屏幕截图
- 网站性能分析
- 等…
总的来说 puppeteer 的出现让 node 出现了更多的可能。希望 node 生态可以越来越好~
当然,调试 node 程序,尤其是有那么多节点和原型链方法的东西,仅仅用终端调试显然不够,所以想更好的调试你们的 node 脚本,可以看下 调试 node 程序工具对比
最后附上请求文档URL的IP情况(getIp是我的文件夹,index.js 就是上面代码的 index.js 代码了~)
完 ~
node爬虫puppeteer使用相关推荐
- Node + ts + puppeteer e2e前端自动化测试
前言: 此文先在其他平台发表,如有雷同,有可能那个也是我~ 先了解一下概念 自动化测试的类型及工具都有挺多:单元测试.集成测试.UI测试.e2e测试等等,相关概念网上有挺多文章介绍了,就不多聊,比如这 ...
- node爬虫爬取小说
node爬虫爬取小说 node爬虫爬取小说 直接上代码 node爬虫爬取小说 最近发现自己喜欢的一个小说无法下载,网页版广告太多,操作太难受,只能自己写个爬虫把内容爬下来放在阅读器里面看 项目下载地址 ...
- node 爬虫 实战 - 爬取拉勾网职位数据
node 爬虫 实战 - 爬取拉勾网职位数据,主要想把数据用于大数据学习,到时候大数据分析可以自己分析一下职位的情况,和比较一些我现在的职位在深圳乃至全国的开发人员水平. 涉及到的技术栈:node.j ...
- node爬虫进阶之——登录
转载自:http://www.jianshu.com/p/87867f325184 在之前的文章node入门场景之--爬虫已经介绍过最简单的node爬虫实现,本文在原先的基础上更进一步,探讨一下如何绕 ...
- node爬虫快速入门
node爬虫 初入前端,刚刚接触node,对于耳闻已久的node爬虫非常神往,所以有了这篇文章,项目代码在文章末尾 需求 抓取天涯论坛重庆地区板块的文章列表信息. 使用工具 node.js super ...
- Node爬虫之使用 async 控制并发
上文 <Node爬虫之使用 eventproxy 控制并发>我们说到用 node 爬了csdn首页数据,但是这些请求完全是并发的,如果某些网站有 "反爬" 机制,就很有 ...
- node爬虫实现文件下载,访问网址
node爬虫实现文件下载, 访问网址 试了下 Node写爬虫,访问速度好像比Java快好多. 同一目录下新建index.js和model.js index.js const model = requi ...
- node爬虫,抓取网页数据
node爬虫,抓取网页数据 1.什么是爬虫? 抓取信息或者数据的程序或者是脚本 2.通过node实现对网页数据的抓取. 安装插件 request,处理请求(此包以被弃用) npm i request ...
- 【华为云实战开发】14.如何使用Node爬虫利器Puppteer进行自动化测试
文:华为云DevCloud 乐少 1.背景 1.1 前端自动化测试较少 前端浏览器众多导致页面兼容性问题比较多,另外界面变化比较快,一个月内可能页面改版两三次,这样导致对前端自动化测试较少,大家也不是 ...
最新文章
- 硬件工程师必备秘籍,模拟电子经典200问!
- 肠道微生物的研究不复杂,不信看这篇Science
- Spring Boot——2分钟构建springweb mvc REST风格HelloWorld
- 【思考?】什么时候会触发这个策略呢?
- .NET MYSQL数据库操作基类( C#源码)
- byteofpython中文gitbook_GitBook 简明教程
- runtime_mysql_users_proxysql的配置系统
- Pytorch——Variable是什么?
- Python 中的 None 与真假
- 数学建模(五)系泊系统设计(16年国赛A题)
- 以四小龙为首的CV企业占比七成,安防AI化已成产业趋势
- 证件照排版软件_证件照的后期处理与打印
- 2-2 李宏毅2021春季机器学习教程-类神经网络训练不起来怎么办(一)局部最小值与鞍点(Local Minima and Saddle Point)
- 投稿流程以及审稿状态
- 饱食沪深港澳22日-港:星级传统韩菜-梨花园~110207
- 信息安全论学习笔记(一):绪论
- Vue-router的使用
- 谷歌浏览器如何正确安装第三方已被停用的扩展插件
- Eclipse创建C++工程并解决“Symbol 'std' could not be solved”
- jquery实现下拉框
热门文章
- 【USACO】贝茜的晨练计划
- Cython与pyx pyd格式-python调用c++
- C语言基础——常用头文件相关函数初步总结
- 【程序设计】Matplotlib绘制黄绿蓝紫色图形
- 在中国,千万别一辈子靠技术生存 !
- java输入数字返回字符串_java Scanner输入数字、字符串
- 大数据分析公司_大数据分析以及处理_提供多种数据服务
- 记录一次Base64.encodeBase64String(data)和BASE64Encoder().encode(data)图片转base64的坑点
- java基础——什么是数组(一维数组、二维数组)
- 为了练习自己的Python基础语法,我用pygame写了一个打砖块闯关的游戏