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 相关文章推荐
用js实现键盘方向键翻页功能的代码
Jun 03 Javascript
通用JS事件写法实现代码
Jan 07 Javascript
javascript 避免闭包引发的问题
Mar 17 Javascript
js实现一个猜数字游戏
Mar 31 Javascript
JS身份证信息验证正则表达式
Jun 12 Javascript
详解基于Node.js的微信JS-SDK后端接口实现代码
Jul 15 Javascript
使用VUE+iView+.Net Core上传图片的方法示例
Jan 04 Javascript
jquery实现点击弹出对话框
Feb 08 jQuery
vue项目中使用vue-layer弹框插件的方法
Mar 11 Javascript
js代码实现轮播图
May 04 Javascript
vue 解决无法对未定义的值,空值或基元值设置反应属性报错问题
Jul 31 Javascript
Webpack的Loader和Plugin的区别
Nov 09 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 strtok()函数的优点分析
2010/03/02 PHP
PHP实现获取域名的方法小结
2014/11/05 PHP
php微信公众号开发(2)百度BAE搭建和数据库使用
2016/12/15 PHP
服务端 VBScript 与 JScript 几个相同特性的写法 By shawl.qiu
2007/03/06 Javascript
Mozilla 表达式 __noSuchMethod__
2009/04/05 Javascript
jquer之ajaxQueue简单实现代码
2011/09/15 Javascript
学习从实践开始之jQuery插件开发 对话框插件开发
2012/04/26 Javascript
jquery代码实现简单的随机图片瀑布流效果
2015/04/20 Javascript
JS组件Bootstrap导航条使用方法详解
2016/04/29 Javascript
Bootstrap实现水平排列的表单
2016/07/04 Javascript
基于jQuery实现弹出可关闭遮罩提示框实例代码
2016/07/18 Javascript
vue如何实现observer和watcher源码解析
2017/03/09 Javascript
关于js的三种使用方式(行内js、内部js、外部js)的程序代码
2018/05/05 Javascript
Vue Autocomplete 自动完成功能简单示例
2019/05/25 Javascript
vue 实现滚动到底部翻页效果(pc端)
2019/07/31 Javascript
理解Proxy及使用Proxy实现vue数据双向绑定操作
2020/07/18 Javascript
详解微信小程序入门从这里出发(登录注册、开发工具、文件及结构介绍)
2020/07/21 Javascript
vue使用svg文件补充-svg放大缩小操作(使用d3.js)
2020/09/22 Javascript
利用python批量给云主机配置安全组的方法教程
2017/06/21 Python
Python3学习笔记之列表方法示例详解
2017/10/06 Python
python版飞机大战代码分享
2018/11/20 Python
python如何以表格形式打印输出的方法示例
2019/06/21 Python
python单例设计模式实现解析
2020/01/07 Python
常用python爬虫库介绍与简要说明
2020/01/25 Python
python怎么对数字进行过滤
2020/07/05 Python
Matplotlib 绘制饼图解决文字重叠的方法
2020/07/24 Python
利用python绘制中国地图(含省界、河流等)
2020/09/21 Python
css3 transform属性详解
2014/09/30 HTML / CSS
学年自我鉴定范文
2013/10/01 职场文书
新闻系毕业生推荐信
2013/11/16 职场文书
旷课检讨书2000字
2014/01/14 职场文书
粗加工管理制度
2014/02/04 职场文书
2016年党员创先争优承诺书
2016/03/25 职场文书
创业计划书之水果店
2019/07/18 职场文书
《女娲补天》读后感5篇
2019/12/31 职场文书
详解Nginx启动失败的几种错误处理
2021/04/01 Servers