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 相关文章推荐
基于jquery的超简单上下翻
Apr 20 Javascript
jQuery幻灯片特效代码分享--鼠标滑过按钮时切换(2)
Nov 18 Javascript
JS非Alert实现网页右下角“未读信息”效果弹窗
Sep 26 Javascript
AngularJS基础 ng-mouseleave 指令详解
Aug 02 Javascript
JSP防止网页刷新重复提交数据的几种方法
Nov 19 Javascript
Bootstrap面板使用方法
Jan 16 Javascript
Angular directive递归实现目录树结构代码实例
May 05 Javascript
详解Vue.js基于$.ajax获取数据并与组件的data绑定
May 26 Javascript
在页面中引入js的两种方法(推荐)
Aug 29 Javascript
JS实现匀加速与匀减速运动的方法示例
Sep 04 Javascript
javascript设计模式 ? 工厂模式原理与应用实例分析
Apr 09 Javascript
vue3语法糖内的defineProps及defineEmits
Apr 14 Vue.js
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
mysql时区问题
2008/03/26 PHP
php array的学习笔记
2012/05/16 PHP
基于php缓存的详解
2013/05/15 PHP
解析php addslashes()与addclashes()函数的区别和比较
2013/06/24 PHP
javascript+php实现根据用户时区显示当地时间的方法
2015/03/11 PHP
Symfony2函数用法实例分析
2016/03/18 PHP
PHP版单点登陆实现方案的实例
2016/11/17 PHP
Yii 访问 Gii(脚手架)时出现 403 错误
2018/06/06 PHP
js模仿windows桌面图标排列算法具体实现(附图)
2013/06/16 Javascript
javascript使用正则控制input输入框允许输入的值方法大全
2014/06/19 Javascript
javascript实现依次输入input自动定焦
2014/12/23 Javascript
SWFObject基本用法实例分析
2015/07/20 Javascript
再次谈论React.js实现原生js拖拽效果引起的一系列问题
2016/04/03 Javascript
老生常谈 js中this的指向
2016/06/30 Javascript
javascript表单正则应用
2017/02/04 Javascript
浅谈JavaScript的innerWidth与innerHeight
2017/10/12 Javascript
Vue实战之vue登录验证的实现代码
2017/10/31 Javascript
浅谈vue-router2路由参数注意的问题
2017/11/08 Javascript
详解微信小程序自定义组件的实现及数据交互
2019/07/22 Javascript
微信小程序音乐播放器开发
2019/11/20 Javascript
基于javascript的无缝滚动动画实现2
2020/08/07 Javascript
JavaScript原生数组函数实例汇总
2020/10/14 Javascript
vant中的toast层级改变操作
2020/11/04 Javascript
uniapp微信小程序:key失效的解决方法
2021/01/20 Javascript
SQLite3中文编码 Python的实现
2017/01/11 Python
利用python如何处理nc数据详解
2018/05/23 Python
Python http接口自动化测试框架实现方法示例
2018/12/06 Python
python reverse反转部分数组的实例
2018/12/13 Python
Django自定义模板过滤器和标签的实现方法
2019/08/21 Python
Spanx塑身衣官网:美国知名内衣品牌
2017/01/11 全球购物
Ibatis如何使用动态表名
2015/07/12 面试题
见习期自我鉴定
2013/11/07 职场文书
工作自荐信
2013/12/11 职场文书
公务员群众路线专题民主生活会发言材料
2014/09/17 职场文书
2014年卫生保健工作总结
2014/12/08 职场文书
初中生思想道德自我评价
2015/03/09 职场文书