node基于puppeteer模拟登录抓取页面的实现


Posted in Javascript onMay 09, 2018

关于热图

在网站分析行业中,网站热图能够很好的反应用户在网站的操作行为,具体分析用户的喜好,对网站进行针对性的优化,一个热图的例子(来源于ptengine)

node基于puppeteer模拟登录抓取页面的实现

上图中能很清晰的看到用户关注点在那,我们不关注产品中热图的功能如何,本篇文章就热图的实现做一下简单的分析和总结。

热图主流的实现方式

一般实现热图显示需要经过如下阶段:
1.获取网站页面
2.获取经过处理后的用户数据
3.绘制热图
 本篇主要聚焦于阶段1来详细的介绍一下主流的在热图中获取网站页面的实现方式
4.使用iframe直接嵌入用户网站
5.抓取用户页面保存到本地,通过iframe嵌入本地资源(所谓本地资源这里认为是分析工具这一端)

两种方式各有各的优缺点

首先第一种直接嵌入用户网站,这个有一定的限制条件,比如如果用户网站为了防止iframe劫持,不允许iframe嵌套(设置meta X-FRAME-OPTIONS 为sameorgin 或者直接设置http header ,甚至直接通过js来控制if(window.top !== window.self){ window.top.location = window.location;} ),这种情况下就需要客户网站做一部分工作才可以被分析工具的iframe加载,使用起来不一定那么方便,因为并不是所有的需要检测分析的网站用户都可以管理网站的。

第二种方式,直接抓取网站页面到本地服务器,然后浏览的是本机服务器上抓取的页面,这种情况下页面已经过来了,我们就可以为所欲为了,首先我们绕过了X-FRAME-OPTIONS 为sameorgin的问题,只需要解决js控制的问题,对于抓取的页面来说,我们可以通过特殊的对应来处理(比如移除对应的js控制,或者添加我们自己的js);但是这种方式也有很多的不足:1、无法抓取spa页面,无法抓取需要用户登录授权的页面,无法抓取用户设置了白明白的页面等等。

两种方式都存在https 和 http资源由于同源策略引起的另一个问题,https站无法加载http资源,所以如果为了最好的兼容性,热图分析工具需要被应用http协议,当然具体可以根据访问的客户网站而具体分站优化。

抓取网站页面如何优化

这里我们针对抓取网站页面遇到的问题基于puppeteer做一些优化,提高抓取成功的概率,主要优化以下两种页面:

1.spa页面

spa页面在当前页算是主流了,但是它总所周知的是其对搜索引擎的不友好;通常的页面抓取程序其实就是一个简单的爬虫,其过程通常都是发起一个http get 请求到用户网站(应该是用户网站服务器)。这种抓取方式本身就会有问题问题,首先,直接请求的是用户服务器,用户服务器对非浏览器的agent 应该会有很多限制,需要绕过处理;其次,请求返回的是原始内容,需要在浏览器中通过js渲染的部分无法获取(当然,在iframe嵌入后,js执行还是会再一定程度上弥补这个问题),最后如果页面是spa页面,那么此时获取的只是模板,在热图中显示效果非常不友好。

针对这种情况,如果基于puppeteer来做,流程就变成了

puppeteer启动浏览器打开用户网站-->页面渲染-->返回渲染后结果,简单的用伪代码实现如下:

const puppeteer = require('puppeteer');

async getHtml = (url) =>{
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(url);
  return await page.content();
}

这样我们拿到的内容就是渲染后的内容,无论页面的渲染方式如何(客户端渲染抑或服务端)

需要登录的页面

对于需要登录页面其实分为多种情况:

需要登录才可以查看页面,如果没有登录,则跳转到login页面(各种管理系统)

对于这种类型的页面我们需要做的就是模拟登录,所谓模拟登录就是让浏览器去登录,这里需要用户提供对应网站的用户名和密码,然后我们走如下的流程:

访问用户网站-->用户网站检测到未登录跳转到login-->puppeteer控制浏览器自动登录后跳转到真正需要抓取的页面,可用如下伪代码来说明:

const puppeteer = require("puppeteer");
async autoLogin =(url)=>{
   const browser = await puppeteer.launch();
   const page =await browser.newPage();
   await page.goto(url);
   await page.waitForNavigation();

   //登录
   await page.type('#username',"用户提供的用户名");
   await page.type('#password','用户提供的密码');

   await page.click('#btn_login');

  //页面登录成功后,需要保证redirect 跳转到请求的页面
   await page.waitForNavigation();

   return await page.content();
}

登录与否都可以查看页面,只是登录后看到内容会所有不同 (各种电商或者portal页面)

这种情况处理会比较简单一些,可以简单的认为是如下步骤:

通过puppeteer启动浏览器打开请求页面-->点击登录按钮-->输入用户名和密码登录 -->重新加载页面

基本代码如下图:

const puppeteer = require("puppeteer");
async autoLoginV2 =(url)=>{
   const browser = await puppeteer.launch();
   const page =await browser.newPage();
   await page.goto(url);

   await page.click('#btn_show_login');

   //登录
   await page.type('#username',"用户提供的用户名");
   await page.type('#password','用户提供的密码');

   await page.click('#btn_login');

  //页面登录成功后,是否需要reload 根据实际情况来确定
   await page.reload();

   return await page.content();
}

总结

明天总结吧,今天下班了。

补充(还昨天的债):基于puppeteer虽然可以很友好的抓取页面内容,但是也存在这很多的局限

1.抓取的内容为渲染后的原始html,即资源路径(css、image、javascript)等都是相对路径,保存到本地后无法正常显示,需要特殊处理(js不需要特殊处理,甚至可以移除,因为渲染的结构已经完成)

2.通过puppeteer抓取页面性能会比直接http get 性能会差一些,因为多了渲染的过程

3.同样无法保证页面的完整性,只是很大的提高了完整的概率,虽然通过page对象提供的各种wait 方法能够解决这个问题,但是网站不同,处理方式就会不同,无法复用。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
浅析offsetLeft,Left,clientLeft之间的区别
Nov 30 Javascript
Jquery中国地图热点效果-鼠标经过弹出提示层信息的简单实例
Feb 12 Javascript
跟我学习javascript的arguments对象
Nov 16 Javascript
jQuery实现的选择商品飞入文本框动画效果完整实例
Aug 10 Javascript
遍历json 对象的属性并且动态添加属性的实现
Dec 02 Javascript
bootstrap输入框组件使用方法详解
Jan 19 Javascript
详解vue父子模版嵌套案例
Mar 04 Javascript
jquery 手势密码插件
Mar 17 Javascript
慕课网题目之js实现抽奖系统功能
Sep 19 Javascript
VueAwesomeSwiper在VUE中的使用以及遇到的一些问题
Jan 11 Javascript
Vue 实现展开折叠效果的示例代码
Aug 27 Javascript
vue实现PC端分辨率适配操作
Aug 03 Javascript
nuxt框架中路由鉴权之Koa和Session的用法
May 09 #Javascript
jQuery简单实现的HTML页面文本框模糊匹配查询功能完整示例
May 09 #jQuery
JS验证输入的是否是数字及保留几位小数问题
May 09 #Javascript
javaScript强制保留两位小数的输入数校验和小数保留问题
May 09 #Javascript
node puppeteer(headless chrome)实现网站登录
May 09 #Javascript
JS中移除非数字最多保留一位小数
May 09 #Javascript
JS关于刷新页面的相关总结
May 09 #Javascript
You might like
php Smarty初体验二 获取配置信息
2011/08/08 PHP
PHP中模拟链表和链表的基本操作示例
2016/02/27 PHP
php实现登陆模块功能示例
2016/10/20 PHP
PHP全功能无变形图片裁剪操作类与用法示例
2017/01/10 PHP
thinkPHP5.0框架自动加载机制分析
2017/03/18 PHP
Js组件的一些写法
2010/09/10 Javascript
JS 操作Array数组的方法及属性实例解析
2014/01/08 Javascript
用队列模拟jquery的动画算法实例
2015/01/20 Javascript
jquery专业的导航菜单特效代码分享
2015/08/29 Javascript
原生js实现日期计算器功能
2017/02/17 Javascript
JavaScript表单验证实现代码
2017/05/22 Javascript
Vue2.0子同级组件之间数据交互方法
2018/02/28 Javascript
5分钟快速掌握JS中var、let和const的异同
2018/09/19 Javascript
JavaScript canvas绘制折线图
2020/02/18 Javascript
详解微信小程序入门从这里出发(登录注册、开发工具、文件及结构介绍)
2020/07/21 Javascript
jQuery实现异步上传一个或多个文件
2020/08/17 jQuery
基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能
2021/01/05 Vue.js
[01:21]DOTA2新纪元-7.0新版本即将开启!
2016/12/11 DOTA
在Docker上部署Python的Flask框架的教程
2015/04/08 Python
Python读取一个目录下所有目录和文件的方法
2016/07/15 Python
flask使用session保存登录状态及拦截未登录请求代码
2018/01/19 Python
从0开始的Python学习016异常
2019/04/08 Python
python实现机器人卡牌
2019/10/06 Python
使用Python实现分别输出每个数组
2019/12/06 Python
TensorFlow查看输入节点和输出节点名称方式
2020/01/04 Python
Django 自定义权限管理系统详解(通过中间件认证)
2020/03/11 Python
python 爬虫如何正确的使用cookie
2020/10/27 Python
图片上传插件ImgUploadJS:用HTML5 File API 实现截图粘贴上传、拖拽上传
2016/01/20 HTML / CSS
上海期货面试题
2014/01/31 面试题
加工操作管理制度
2014/01/19 职场文书
3的组成教学反思
2014/04/30 职场文书
国庆横幅标语
2014/10/08 职场文书
南京导游词
2015/02/03 职场文书
入党转正申请书范文
2019/05/20 职场文书
Python还能这么玩之只用30行代码从excel提取个人值班表
2021/06/05 Python
python中的random模块和相关函数详解
2022/04/22 Python