相关文章推荐
爱运动的投影仪  ·  public class ...·  1 月前    · 
老实的橙子  ·  python ...·  1 年前    · 
发呆的拖把  ·  编译器错误 CS0518 | ...·  1 年前    · 

Puppeteer使用中的那些坑

由于近期一个项目中需要采集一批数据进行分析,手头暂时并没有团队,所以干了一阵抓数据的工作。

为什么会采用puppeteer?

万事开头难,选择什么方式采集数据是项目的第一步。最开始的想法是抓包进行分析,但是目标网站数量过于庞大,自己一个人干显然有点扛不住。更何况,后续的分析和建模型才是项目的重头戏,想想还是前边做得简单一点,留点力气后边搬砖。

当然,最重要的原因其实是,某几个网站的反爬实在是看得头都大了。

所以,世上无难事,只要肯放弃。果断选择无头浏览器采集(事实上,也有很多针对无头浏览器的反爬机制,以后有机会再讲)

于是,就有以下如下几个选择:

phantomjs: 据说已经不维护了,果断放弃

selenium: 成熟稳定,支持更多语言,但是容易触发针对selenium的一些反爬机制

puppeteer: 性能和灵活性较高,但需要nodejs开发

事实上,最开始的想法是selenium,毕竟更成熟一些。但是,在尝试用selenium控制chroomeheadless之后,比较容易被一些网站识别为爬虫。而尝试切换为firefox之后,却发现性能并不理想。

所以,最终决定采用puppeteer了。

不要使用pyppeteer!

由于项目的主体部分打算用python来写,再加上自己很少写nodejs,所以首先想到的是能否在python下实现。于是,网上各种不靠谱的技术博客纷纷推荐了pyppeteer。

事实证明,这是个坑!!!无论你有多不愿意写nodejs的回调,也不要用pyppeteer。因为,你会发现用pyppeteer根!本!行!不!通!

pyppeteer已经太多年没人维护了,放弃它吧!

如何提升puppeteer的效率

第一个步当然是调整puppeteer启动浏览器的参数,百度上能够找到的内容不赘述。

第二步,则是如何提升系统的并发量。chrome只会使用一个核,那么怎么更充分地发挥性能呢?

当然是启动更多的浏览器!

稳定的做法是对于每个页面单独启动浏览器,然后抓取之后再关闭。事实上,这也是官方文档中的方法。而且,github上也有一个相关的项目: puppeteer-cluster

但是,采用这种方式可能会带来两个问题。其一,频繁启动和关闭浏览器肯定会带来性能消耗,这样肯定限制了浏览器的速度;其二,通过不同浏览器打开关联页面,有可能触发部分网站的反爬机制。

可不可以仅维持几个浏览器,让所有的页面都通过这几个浏览器打开呢?当然可以,具体的操作后边展开来讲

第三步,用好puppeteer的拦截器和等待机制。

绝大多数情况下,我们并不需要网站的所有信息。那么,对于不需要的信息(图片、样式、js等),可以选择拦截。不过,这里需要注意的一点是,对于js的拦截需要慎重,可能导致无法抓取目标网站。那么,对于不同网站采用怎样的拦截策略,可以考虑通过配置文件的方式实现。

等待机制不仅可以使网站适时关闭,同时还能够确保抓取到目标网站,避免跳转到反爬页面等清空对爬虫造成的影响。


监控浏览器状态

如果选择长时间打开浏览器,而这个抓取过程又要持续很久的话。那么,监控浏览器状态就必不可少了(比如我的这个项目)

在我自己的项目中,主要监控三方面内容:其一,监控浏览器tab页打开的数量,防止数量过多引发的崩溃;其二,确保浏览器没有卡死,依然在持续抓取页面;其三,监控浏览器打开和关闭状态,方式并发下同时打开或关闭多个浏览器。

1.tab页数量监控

对于tab页数量监控的问题,puppeteer中提供了一个browser.pages的方法,可以获取浏览器打开页面的列表。例如

let pageNum = await browser.pages();

但是,在await的过程中,有可能会有其他的协程打开或关闭页面。而且,实测该方法似乎有一定的滞后性。所以,并不推荐采用这种方式。

靠谱的方案是控制爬虫并发量,从而确保打开的页面在控制范围内。

我在项目中维护了一个数组,记录每个浏览器打开的页面数量。当有新页面打开时,对应数量加一;而如果页面关闭,则减一。同时,如果浏览器重启,则设置为0。

2.监控浏览器是否卡死

监控浏览器是否卡死可以考虑用redis实现,当浏览器有抓取动作,则在redis中保存一个键值对。而这个键值对需要设置过期时间。

监控模块定期查询redis中是否存在各浏览器的键值对,如果某个浏览器在redis中对应的key不存在,则重启该浏览器。

3.监控浏览器打开和关闭状态

这里考虑通过锁实现,确保同一时间只有一个协程打开或关闭浏览器。

发布于 2020-08-18 20:44

文章被以下专栏收录