关于小程序查学位房功能的总结
前提
最近接到的一个需求,就是小程序通过调用其他网站的接口获取数据,一开始是想通过后端去爬数据,但存在跨域cookie验证不通过,token无法拿到等问题。于是有了这个备用方案,通过node搭一个中间件去获取数据。这里用到eggjs+Puppeteer。
Puppeteer的介绍
Puppeteer是谷歌官方出品的一个通过DevTools协议控制headless Chrome的Node库。可以通过Puppeteer的提供的api直接控制Chrome模拟大部分用户操作来进行UI Test或者作为爬虫访问页面来收集数据。本文大部分依赖page提供的接口
如何与eggjs结合
第一个需求是从深圳居住证平台 房屋编码查询 - 深圳经济特区居住证服务平台 -查询房屋编码。从提交的请求可知,每一次打开生成的session是与验证码绑定的。

因而我们在每次打开小程序时,需要先调用eggjs的一个接口去打开上述的页面,进而返回页面对应的cookie。
第二个需求是从各个区的房屋编码查询网站中获取数据,我们进入这个网站可知,每一次打开时都会生成一个session,而请求所用到的token是与session绑定的,而请求所用到的参数FWTYPE和FWBM都是页面上的type和code通过编码加密得到的。那么我们只要获取到这个token,然后在小程序中对对应的参数加密提交,就可以解决了。


所以我们可以用page.evaluate,该函数可以让我们使用内置的 DOM 选择器。而正好每次要用到的token都会存在页面的js中。

代码如下:
然而这些网站都对请求做了拦截,不可以直接调用。

那么我们只能退而求其次,我们通过分析网站的代码可知,网站只会显示房屋地址和锁定结果。所以我们可以通过模拟运行来获取页面元素,进而获取到锁定结果并返回,具体代码如下:
关于并发的解决方案
这样的实现,每一次请求都去产生一个 puppeteer 实例。来一个请求就打开一个chrome。这本身就是一个非常消耗性能的行为。当运行一定数量的 puppeteer 实例之后 ,就会报EventEmitter的错。那么怎么解决呢? 从google查询可知,可以用 generic-pool 来解决。 这是一个基于 Promise 的通用链接池库。有了他之后我们就可以将 puppeteer 实例放在我们的链接池中,如果有请求进来,那么就去池子里面去取一个实例。我们可以设置实例的上限,和常驻池中的实例数量。
在eggjs中增加入口文件app.js
PS: 结合 egg.js 使用时,需要手动指定 workers 数量为 1: egg-scripts start —daemon —workers=1 不然会启动 pool.max * workers 数量的 Puppeteer 实例。
关于部署
Puppeteer在centos上需做一些配置才能部署成功
1. 在cnpm安装后可运行查看是否缺少哪些依赖(版本号可能不同)
2. 安装缺失的依赖库
3. puppeteer.launch需要增加以下配置
总结
这是本人第一次把Puppeteer用于项目中,其中还是有很大的优化空间的,比如Puppeteer的启动项、执行流程、接口的完善等。 Puppeteer除了模拟获取数据外,本身还是一个强大的自动化测试工具,未来可以在小程序中加入自动化测试用例,生成测试报告,并入到小程序的工程化中。
参考文章
Last updated
Was this helpful?